diff --git a/grub-core/commands/appendedsig/appendedsig.c b/grub-core/commands/appendedsig/appendedsig.c index ca54c90fa..0c4c788ff 100644 --- a/grub-core/commands/appendedsig/appendedsig.c +++ b/grub-core/commands/appendedsig/appendedsig.c @@ -34,6 +34,7 @@ #include #include #include +#include #include "appendedsig.h" @@ -46,6 +47,11 @@ GRUB_MOD_LICENSE ("GPLv3+"); #define SIG_MAGIC "~Module signature appended~\n" #define SIG_MAGIC_SIZE ((sizeof(SIG_MAGIC) - 1)) +/* SHA256, SHA384 and SHA512 hash sizes. */ +#define SHA256_HASH_SIZE 32 +#define SHA384_HASH_SIZE 48 +#define SHA512_HASH_SIZE 64 + /* * This structure is extracted from scripts/sign-file.c in the linux kernel * source. It was licensed as LGPLv2.1+, which is GPLv3+ compatible. @@ -79,11 +85,23 @@ struct sb_database { grub_x509_cert_t *certs; /* Certificates. */ grub_uint32_t cert_entries; /* Number of certificates. */ + grub_uint8_t **hashes; /* Certificate/binary hashes. */ + grub_size_t *hash_sizes; /* Sizes of certificate/binary hashes. */ + grub_uint32_t hash_entries; /* Number of certificate/binary hashes. */ + bool is_db; /* Flag to indicate the db/dbx list. */ }; typedef struct sb_database sb_database_t; /* The db list is used to validate appended signatures. */ -static sb_database_t db = {.certs = NULL, .cert_entries = 0}; +static sb_database_t db = {.certs = NULL, .cert_entries = 0, .hashes = NULL, + .hash_sizes = NULL, .hash_entries = 0, .is_db = true}; +/* + * The dbx list is used to ensure that the distrusted certificates or GRUB + * modules/kernel binaries are rejected during appended signatures/hashes + * validation. + */ +static sb_database_t dbx = {.certs = NULL, .cert_entries = 0, .hashes = NULL, + .hash_sizes = NULL, .hash_entries = 0, .is_db = false}; /* * Signature verification flag (check_sigs). @@ -118,6 +136,169 @@ static struct grub_fs pseudo_fs = { .fs_read = pseudo_read }; +/* + * GUID can be used to determine the hashing function and generate the hash using + * determined hashing function. + */ +static grub_err_t +get_hash (const grub_packed_guid_t *guid, const grub_uint8_t *data, const grub_size_t data_size, + grub_uint8_t *hash, grub_size_t *hash_size) +{ + gcry_md_spec_t *hash_func = NULL; + + if (guid == NULL) + return grub_error (GRUB_ERR_OUT_OF_RANGE, "GUID is not available"); + + if (grub_memcmp (guid, &GRUB_PKS_CERT_SHA256_GUID, GRUB_PACKED_GUID_SIZE) == 0 || + grub_memcmp (guid, &GRUB_PKS_CERT_X509_SHA256_GUID, GRUB_PACKED_GUID_SIZE) == 0) + hash_func = &_gcry_digest_spec_sha256; + else if (grub_memcmp (guid, &GRUB_PKS_CERT_SHA384_GUID, GRUB_PACKED_GUID_SIZE) == 0 || + grub_memcmp (guid, &GRUB_PKS_CERT_X509_SHA384_GUID, GRUB_PACKED_GUID_SIZE) == 0) + hash_func = &_gcry_digest_spec_sha384; + else if (grub_memcmp (guid, &GRUB_PKS_CERT_SHA512_GUID, GRUB_PACKED_GUID_SIZE) == 0 || + grub_memcmp (guid, &GRUB_PKS_CERT_X509_SHA512_GUID, GRUB_PACKED_GUID_SIZE) == 0) + hash_func = &_gcry_digest_spec_sha512; + else + return grub_error (GRUB_ERR_OUT_OF_RANGE, "unsupported GUID hash"); + + grub_crypto_hash (hash_func, hash, data, data_size); + *hash_size = hash_func->mdlen; + + return GRUB_ERR_NONE; +} + +static grub_err_t +generate_cert_hash (const grub_size_t cert_hash_size, const grub_uint8_t *data, + const grub_size_t data_size, grub_uint8_t *hash, grub_size_t *hash_size) +{ + grub_packed_guid_t guid = { 0 }; + + /* support SHA256, SHA384 and SHA512 for certificate hash */ + if (cert_hash_size == SHA256_HASH_SIZE) + grub_memcpy (&guid, &GRUB_PKS_CERT_X509_SHA256_GUID, GRUB_PACKED_GUID_SIZE); + else if (cert_hash_size == SHA384_HASH_SIZE) + grub_memcpy (&guid, &GRUB_PKS_CERT_X509_SHA384_GUID, GRUB_PACKED_GUID_SIZE); + else if (cert_hash_size == SHA512_HASH_SIZE) + grub_memcpy (&guid, &GRUB_PKS_CERT_X509_SHA512_GUID, GRUB_PACKED_GUID_SIZE); + else + { + grub_dprintf ("appendedsig", "unsupported hash type (%" PRIuGRUB_SIZE ") and " + "skipped\n", cert_hash_size); + return GRUB_ERR_UNKNOWN_COMMAND; + } + + return get_hash (&guid, data, data_size, hash, hash_size); +} + +/* Check the hash presence in the db/dbx list. */ +static bool +check_hash_presence (grub_uint8_t *const hash, const grub_size_t hash_size, + const sb_database_t *sb_database) +{ + grub_uint32_t i; + + for (i = 0; i < sb_database->hash_entries; i++) + { + if (sb_database->hashes[i] == NULL) + continue; + + if (hash_size == sb_database->hash_sizes[i] && + grub_memcmp (sb_database->hashes[i], hash, hash_size) == 0) + return true; + } + + return false; +} + +/* Add the certificate/binary hash into the db/dbx list. */ +static grub_err_t +add_hash (grub_uint8_t *const data, const grub_size_t data_size, sb_database_t *sb_database) +{ + grub_uint8_t **hashes; + grub_size_t *hash_sizes; + + if (data == NULL || data_size == 0) + return grub_error (GRUB_ERR_OUT_OF_RANGE, "certificate/binary-hash data or size is not available"); + + if (sb_database->is_db == true) + { + if (check_hash_presence (data, data_size, &dbx) == true) + { + grub_dprintf ("appendedsig", + "cannot add a hash (%02x%02x%02x%02x), as it is present in the dbx list\n", + data[0], data[1], data[2], data[3]); + return GRUB_ERR_ACCESS_DENIED; + } + } + + if (check_hash_presence (data, data_size, sb_database) == true) + { + grub_dprintf ("appendedsig", + "cannot add a hash (%02x%02x%02x%02x), as it is present in the %s list\n", + data[0], data[1], data[2], data[3], ((sb_database->is_db == true) ? "db" : "dbx")); + return GRUB_ERR_EXISTS; + } + + hashes = grub_realloc (sb_database->hashes, sizeof (grub_uint8_t *) * (sb_database->hash_entries + 1)); + if (hashes == NULL) + return grub_error (GRUB_ERR_OUT_OF_MEMORY, "out of memory"); + + hash_sizes = grub_realloc (sb_database->hash_sizes, sizeof (grub_size_t) * (sb_database->hash_entries + 1)); + if (hash_sizes == NULL) + { + /* Allocated memory will be freed by free_db_list()/free_dbx_list(). */ + hashes[sb_database->hash_entries] = NULL; + sb_database->hashes = hashes; + sb_database->hash_entries++; + + return grub_error (GRUB_ERR_OUT_OF_MEMORY, "out of memory"); + } + + hashes[sb_database->hash_entries] = grub_malloc (data_size); + if (hashes[sb_database->hash_entries] == NULL) + return grub_error (GRUB_ERR_OUT_OF_MEMORY, "out of memory"); + + grub_dprintf ("appendedsig", + "added the hash %02x%02x%02x%02x... with size of %" PRIuGRUB_SIZE " to the %s list\n", + data[0], data[1], data[2], data[3], data_size, + ((sb_database->is_db == true) ? "db" : "dbx")); + + grub_memcpy (hashes[sb_database->hash_entries], data, data_size); + hash_sizes[sb_database->hash_entries] = data_size; + sb_database->hash_sizes = hash_sizes; + sb_database->hashes = hashes; + sb_database->hash_entries++; + + return GRUB_ERR_NONE; +} + +static bool +is_hash (const grub_packed_guid_t *guid) +{ + /* GUID type of the binary hash. */ + if (grub_memcmp (guid, &GRUB_PKS_CERT_SHA256_GUID, GRUB_PACKED_GUID_SIZE) == 0 || + grub_memcmp (guid, &GRUB_PKS_CERT_SHA384_GUID, GRUB_PACKED_GUID_SIZE) == 0 || + grub_memcmp (guid, &GRUB_PKS_CERT_SHA512_GUID, GRUB_PACKED_GUID_SIZE) == 0) + return true; + + /* GUID type of the certificate hash. */ + if (grub_memcmp (guid, &GRUB_PKS_CERT_X509_SHA256_GUID, GRUB_PACKED_GUID_SIZE) == 0 || + grub_memcmp (guid, &GRUB_PKS_CERT_X509_SHA384_GUID, GRUB_PACKED_GUID_SIZE) == 0 || + grub_memcmp (guid, &GRUB_PKS_CERT_X509_SHA512_GUID, GRUB_PACKED_GUID_SIZE) == 0) + return true; + + return false; +} + +static bool +is_x509 (const grub_packed_guid_t *guid) +{ + if (grub_memcmp (guid, &GRUB_PKS_CERT_X509_GUID, GRUB_PACKED_GUID_SIZE) == 0) + return true; + + return false; +} + static bool is_cert_match (const grub_x509_cert_t *cert1, const grub_x509_cert_t *cert2) { @@ -136,7 +317,33 @@ is_cert_match (const grub_x509_cert_t *cert1, const grub_x509_cert_t *cert2) return false; } -/* Check the certificate presence in the db list. */ +/* Check the certificate hash presence in the dbx list. */ +static bool +is_cert_hash_present_in_dbx (const grub_uint8_t *data, const grub_size_t data_size) +{ + grub_err_t rc; + grub_uint32_t i; + grub_size_t cert_hash_size = 0; + grub_uint8_t cert_hash[GRUB_MAX_HASH_LEN] = { 0 }; + + for (i = 0; i < dbx.hash_entries; i++) + { + if (dbx.hashes[i] == NULL) + continue; + + rc = generate_cert_hash (dbx.hash_sizes[i], data, data_size, cert_hash, &cert_hash_size); + if (rc != GRUB_ERR_NONE) + continue; + + if (cert_hash_size == dbx.hash_sizes[i] && + grub_memcmp (dbx.hashes[i], cert_hash, cert_hash_size) == 0) + return true; + } + + return false; +} + +/* Check the certificate presence in the db/dbx list. */ static bool check_cert_presence (const grub_x509_cert_t *cert_in, const sb_database_t *sb_database) { @@ -149,7 +356,11 @@ check_cert_presence (const grub_x509_cert_t *cert_in, const sb_database_t *sb_da return false; } -/* Add the certificate into the db list */ +/* + * Add the certificate into the db list if it is not present in the dbx and db + * list when is_db is true. Add the certificate into the dbx list when is_db is + * false. + */ static grub_err_t add_certificate (const grub_uint8_t *data, const grub_size_t data_size, sb_database_t *sb_database) @@ -167,30 +378,54 @@ add_certificate (const grub_uint8_t *data, const grub_size_t data_size, rc = grub_x509_cert_parse (data, data_size, cert); if (rc != GRUB_ERR_NONE) { - grub_dprintf ("appendedsig", "cannot add a certificate CN='%s' to the db list\n", - cert->subject); + grub_dprintf ("appendedsig", "cannot add a certificate CN='%s' to the %s list\n", + cert->subject, (sb_database->is_db == true) ? "db" : "dbx"); grub_free (cert); return rc; } + /* + * Only checks the certificate against dbx if is_db is true when dynamic key + * management is enabled. + */ + if (append_key_mgmt == true) + { + if (sb_database->is_db == true) + { + if (is_cert_hash_present_in_dbx (data, data_size) == true || + check_cert_presence (cert, &dbx) == true) + { + grub_dprintf ("appendedsig", + "cannot add a certificate CN='%s', as it is present in the dbx list", + cert->subject); + rc = GRUB_ERR_ACCESS_DENIED; + goto fail; + } + } + } + if (check_cert_presence (cert, sb_database) == true) { grub_dprintf ("appendedsig", - "cannot add a certificate CN='%s', as it is present in the db list", - cert->subject); - grub_x509_cert_release (cert); - grub_free (cert); - - return GRUB_ERR_EXISTS; + "cannot add a certificate CN='%s', as it is present in the %s list", + cert->subject, ((sb_database->is_db == true) ? "db" : "dbx")); + rc = GRUB_ERR_EXISTS; + goto fail; } - grub_dprintf ("appendedsig", "added a certificate CN='%s' to the db list\n", - cert->subject); + grub_dprintf ("appendedsig", "added a certificate CN='%s' to the %s list\n", + cert->subject, ((sb_database->is_db == true) ? "db" : "dbx")); cert->next = sb_database->certs; sb_database->certs = cert; sb_database->cert_entries++; + return rc; + + fail: + grub_x509_cert_release (cert); + grub_free (cert); + return rc; } @@ -382,6 +617,68 @@ grub_verify_appended_signature (const grub_uint8_t *buf, grub_size_t bufsize) return err; } +/* Add the X.509 certificates/binary hash to the db list from PKS. */ +static grub_err_t +load_pks2db (void) +{ + grub_err_t rc; + grub_uint32_t i; + + for (i = 0; i < pks_keystore->db_entries; i++) + { + if (is_hash (&pks_keystore->db[i].guid) == true) + { + rc = add_hash (pks_keystore->db[i].data, + pks_keystore->db[i].data_size, &db); + if (rc == GRUB_ERR_OUT_OF_MEMORY) + return rc; + } + else if (is_x509 (&pks_keystore->db[i].guid) == true) + { + rc = add_certificate (pks_keystore->db[i].data, + pks_keystore->db[i].data_size, &db); + if (rc == GRUB_ERR_OUT_OF_MEMORY) + return rc; + } + else + grub_dprintf ("appendedsig", "unsupported signature data type and " + "skipped (%u)\n", i + 1); + } + + return GRUB_ERR_NONE; +} + +/* Add the certificates and certificate/binary hash to the dbx list from PKS. */ +static grub_err_t +load_pks2dbx (void) +{ + grub_err_t rc; + grub_uint32_t i; + + for (i = 0; i < pks_keystore->dbx_entries; i++) + { + if (is_x509 (&pks_keystore->dbx[i].guid) == true) + { + rc = add_certificate (pks_keystore->dbx[i].data, + pks_keystore->dbx[i].data_size, &dbx); + if (rc == GRUB_ERR_OUT_OF_MEMORY) + return rc; + } + else if (is_hash (&pks_keystore->dbx[i].guid) == true) + { + rc = add_hash (pks_keystore->dbx[i].data, + pks_keystore->dbx[i].data_size, &dbx); + if (rc != GRUB_ERR_NONE) + return rc; + } + else + grub_dprintf ("appendedsig", "unsupported signature data type and " + "skipped (%u)\n", i + 1); + } + + return GRUB_ERR_NONE; +} + /* * Extract the X.509 certificates from the ELF Note header, parse it, and add * it to the db list. @@ -422,11 +719,45 @@ load_elf2db (void) } } +/* + * Extract trusted and distrusted keys from PKS and store them in the db and + * dbx list. + */ +static void +create_dbs_from_pks (void) +{ + grub_err_t err; + + err = load_pks2dbx (); + if (err != GRUB_ERR_NONE) + grub_printf ("warning: dbx list might not be fully populated\n"); + + /* + * If db does not exist in the PKS storage, then read the static keys as a db + * default keys from the GRUB ELF Note and add them into the db list. + */ + if (pks_keystore->db_exists == false) + load_elf2db (); + else + { + err = load_pks2db (); + if (err != GRUB_ERR_NONE) + grub_printf ("warning: db list might not be fully populated\n"); + } + + grub_pks_free_data (); + grub_dprintf ("appendedsig", "the db list now has %u keys\n" + "the dbx list now has %u keys\n", + db.hash_entries + db.cert_entries, + dbx.hash_entries + dbx.cert_entries); +} + /* Free db list memory */ static void free_db_list (void) { grub_x509_cert_t *cert; + grub_uint32_t i; while (db.certs != NULL) { @@ -436,9 +767,37 @@ free_db_list (void) grub_free (cert); } + for (i = 0; i < db.hash_entries; i++) + grub_free (db.hashes[i]); + + grub_free (db.hashes); + grub_free (db.hash_sizes); grub_memset (&db, 0, sizeof (sb_database_t)); } +/* Free dbx list memory */ +static void +free_dbx_list (void) +{ + grub_x509_cert_t *cert; + grub_uint32_t i; + + while (dbx.certs != NULL) + { + cert = dbx.certs; + dbx.certs = dbx.certs->next; + grub_x509_cert_release (cert); + grub_free (cert); + } + + for (i = 0; i < dbx.hash_entries; i++) + grub_free (dbx.hashes[i]); + + grub_free (dbx.hashes); + grub_free (dbx.hash_sizes); + grub_memset (&dbx, 0, sizeof (sb_database_t)); +} + static const char * grub_env_read_sec (struct grub_env_var *var __attribute__ ((unused)), const char *val __attribute__ ((unused))) @@ -631,10 +990,23 @@ GRUB_MOD_INIT (appendedsig) if (rc != ASN1_SUCCESS) grub_fatal ("error initing ASN.1 data structures: %d: %s\n", rc, asn1_strerror (rc)); - /* Extract trusted keys from ELF Note and store them in the db. */ - load_elf2db (); - grub_dprintf ("appendedsig", "the db list now has %u static keys\n", - db.cert_entries); + /* + * If signature verification is enabled with the dynamic key management, + * extract trusted and distrusted keys from PKS and store them in the db + * and dbx list. + */ + if (append_key_mgmt == true) + create_dbs_from_pks (); + /* + * If signature verification is enabled with the static key management, + * extract trusted keys from ELF Note and store them in the db list. + */ + else + { + load_elf2db (); + grub_dprintf ("appendedsig", "the db list now has %u static keys\n", + db.cert_entries); + } grub_verifier_register (&grub_appendedsig_verifier); grub_dl_set_persistent (mod); @@ -648,6 +1020,7 @@ GRUB_MOD_FINI (appendedsig) */ free_db_list (); + free_dbx_list (); grub_register_variable_hook ("check_appended_signatures", NULL, NULL); grub_env_unset ("check_appended_signatures"); grub_register_variable_hook ("appendedsig_key_mgmt", NULL, NULL); diff --git a/include/grub/efi/pks.h b/include/grub/efi/pks.h new file mode 100644 index 000000000..ff306f591 --- /dev/null +++ b/include/grub/efi/pks.h @@ -0,0 +1,112 @@ +/* + * Copyright (c) 2006 - 2015, Intel Corporation. All rights reserved. This + * program and the accompanying materials are licensed and made available + * under the terms and conditions of the 2-Clause BSD License which + * accompanies this distribution. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * https://github.com/tianocore/edk2-staging (edk2-staging repo of tianocore), + * the ImageAuthentication.h file under it, and here's the copyright and license. + * + * MdePkg/Include/Guid/ImageAuthentication.h + * + * Copyright 2022, 2023, 2024, 2025 IBM Corp. + */ + +#ifndef PKS_HEADER +#define PKS_HEADER 1 + +#include + +/* + * It is derived from EFI_CERT_X509_GUID. + * https://github.com/tianocore/edk2-staging/blob/master/MdePkg/Include/Guid/ImageAuthentication.h + */ +#define GRUB_PKS_CERT_X509_GUID \ + (grub_guid_t) \ + { 0xa159c0a5, 0xe494, 0xa74a, \ + { 0x87, 0xb5, 0xab, 0x15, 0x5c, 0x2b, 0xf0, 0x72 } \ + } + +/* + * It is derived from EFI_CERT_SHA256_GUID. + * https://github.com/tianocore/edk2-staging/blob/master/MdePkg/Include/Guid/ImageAuthentication.h + */ +#define GRUB_PKS_CERT_SHA256_GUID \ + (grub_guid_t) \ + { 0x2616c4c1, 0x4c50, 0x9240, \ + { 0xac, 0xa9, 0x41, 0xf9, 0x36, 0x93, 0x43, 0x28 } \ + } + +/* + * It is derived from EFI_CERT_SHA384_GUID. + * https://github.com/tianocore/edk2-staging/blob/master/MdePkg/Include/Guid/ImageAuthentication.h + */ +#define GRUB_PKS_CERT_SHA384_GUID \ + (grub_guid_t) \ + { 0x07533eff, 0xd09f, 0xc948, \ + { 0x85, 0xf1, 0x8a, 0xd5, 0x6c, 0x70, 0x1e, 0x1 } \ + } + +/* + * It is derived from EFI_CERT_SHA512_GUID. + * https://github.com/tianocore/edk2-staging/blob/master/MdePkg/Include/Guid/ImageAuthentication.h + */ +#define GRUB_PKS_CERT_SHA512_GUID \ + (grub_guid_t) \ + { 0xae0f3e09, 0xc4a6, 0x504f, \ + { 0x9f, 0x1b, 0xd4, 0x1e, 0x2b, 0x89, 0xc1, 0x9a } \ + } + +/* + * It is derived from EFI_CERT_X509_SHA256_GUID. + * https://github.com/tianocore/edk2-staging/blob/master/MdePkg/Include/Guid/ImageAuthentication.h + */ +#define GRUB_PKS_CERT_X509_SHA256_GUID \ + (grub_guid_t) \ + { 0x92a4d23b, 0xc096, 0x7940, \ + { 0xb4, 0x20, 0xfc, 0xf9, 0x8e, 0xf1, 0x03, 0xed } \ + } + +/* + * It is derived from EFI_CERT_X509_SHA384_GUID. + * https://github.com/tianocore/edk2-staging/blob/master/MdePkg/Include/Guid/ImageAuthentication.h + */ +#define GRUB_PKS_CERT_X509_SHA384_GUID \ + (grub_guid_t) \ + { 0x6e877670, 0xc280, 0xe64e, \ + { 0xaa, 0xd2, 0x28, 0xb3, 0x49, 0xa6, 0x86, 0x5b } \ + } + +/* + * It is derived from EFI_CERT_X509_SHA512_GUID. + * https://github.com/tianocore/edk2-staging/blob/master/MdePkg/Include/Guid/ImageAuthentication.h + */ +#define GRUB_PKS_CERT_X509_SHA512_GUID \ + (grub_guid_t) \ + { 0x63bf6d44, 0x0225, 0xda4c, \ + { 0xbc, 0xfa, 0x24, 0x65, 0xd2, 0xb0, 0xfe, 0x9d } \ + } + +#endif diff --git a/include/grub/types.h b/include/grub/types.h index 45079bf65..b3ba762fc 100644 --- a/include/grub/types.h +++ b/include/grub/types.h @@ -379,6 +379,8 @@ struct grub_guid } __attribute__ ((aligned(4))); typedef struct grub_guid grub_guid_t; +#define GRUB_GUID_SIZE (sizeof (grub_guid_t)) + struct grub_packed_guid { grub_uint32_t data1; @@ -388,4 +390,6 @@ struct grub_packed_guid } GRUB_PACKED; typedef struct grub_packed_guid grub_packed_guid_t; +#define GRUB_PACKED_GUID_SIZE (sizeof (grub_packed_guid_t)) + #endif /* ! GRUB_TYPES_HEADER */