diff options
author | Baitinq <manuelpalenzuelamerino@gmail.com> | 2022-09-26 20:09:07 +0200 |
---|---|---|
committer | Baitinq <manuelpalenzuelamerino@gmail.com> | 2022-09-26 20:09:07 +0200 |
commit | dbb12c09158b492dcfe62056f28f7317d97e0bb3 (patch) | |
tree | aa92a5c6d82dcbfcd568c78e4c979755f21aabde | |
parent | Module: Virtualisation: Replace docker with podman (diff) | |
download | nixos-config-dbb12c09158b492dcfe62056f28f7317d97e0bb3.tar.gz nixos-config-dbb12c09158b492dcfe62056f28f7317d97e0bb3.tar.bz2 nixos-config-dbb12c09158b492dcfe62056f28f7317d97e0bb3.zip |
Overlays: Base: Grub2: Support luks2 with patch
-rw-r--r-- | overlays/base/default.nix | 6 | ||||
-rw-r--r-- | overlays/base/patches/grub-install_luks2.patch | 305 |
2 files changed, 311 insertions, 0 deletions
diff --git a/overlays/base/default.nix b/overlays/base/default.nix index f2773f6..5e2b0df 100644 --- a/overlays/base/default.nix +++ b/overlays/base/default.nix @@ -87,4 +87,10 @@ final: prev: }); }); + grub2 = prev.grub2.overrideAttrs (oldAttrs: { + patches = oldAttrs.patches ++ [ + ./patches/grub-install_luks2.patch + ]; + }); + } diff --git a/overlays/base/patches/grub-install_luks2.patch b/overlays/base/patches/grub-install_luks2.patch new file mode 100644 index 0000000..4b4bacc --- /dev/null +++ b/overlays/base/patches/grub-install_luks2.patch @@ -0,0 +1,305 @@ +diff --git a/grub-core/disk/luks2.c b/grub-core/disk/luks2.c +index 4ee5aeaad..e3eca68ca 100644 +--- a/grub-core/disk/luks2.c ++++ b/grub-core/disk/luks2.c +@@ -353,8 +353,16 @@ luks2_scan (grub_disk_t disk, grub_cryptomount_args_t cargs) + { + grub_cryptodisk_t cryptodisk; + grub_luks2_header_t header; ++ grub_luks2_keyslot_t keyslot; ++ grub_luks2_digest_t digest; ++ grub_luks2_segment_t segment; ++ char cipher[32], *json_header = NULL, *ptr; ++ grub_size_t candidate_key_len = 0, json_idx, size; + char uuid[sizeof (header.uuid) + 1]; + grub_size_t i, j; ++ grub_err_t ret; ++ gcry_md_spec_t *hash = NULL; ++ grub_json_t *json = NULL, keyslots; + + if (cargs->check_boot) + return NULL; +@@ -364,6 +372,175 @@ luks2_scan (grub_disk_t disk, grub_cryptomount_args_t cargs) + grub_errno = GRUB_ERR_NONE; + return NULL; + } ++ json_header = grub_zalloc (grub_be_to_cpu64 (header.hdr_size) - sizeof (header)); ++ if (!json_header) ++ return GRUB_ERR_OUT_OF_MEMORY; ++ ++ /* Read the JSON area. */ ++ ret = grub_disk_read (disk, 0, grub_be_to_cpu64 (header.hdr_offset) + sizeof (header), ++ grub_be_to_cpu64 (header.hdr_size) - sizeof (header), json_header); ++ if (ret) ++ goto err; ++ ++ ptr = grub_memchr (json_header, 0, grub_be_to_cpu64 (header.hdr_size) - sizeof (header)); ++ if (!ptr) ++ goto err; ++ ++ ret = grub_json_parse (&json, json_header, grub_be_to_cpu64 (header.hdr_size)); ++ if (ret) ++ { ++ ret = grub_error (GRUB_ERR_BAD_ARGUMENT, "Invalid LUKS2 JSON header"); ++ goto err; ++ } ++ ++ if (grub_json_getvalue (&keyslots, json, "keyslots") || ++ grub_json_getsize (&size, &keyslots)) ++ { ++ ret = grub_error (GRUB_ERR_BAD_ARGUMENT, "Could not get keyslots"); ++ goto err; ++ } ++ ++ if (grub_disk_native_sectors (disk) == GRUB_DISK_SIZE_UNKNOWN) ++ { ++ /* FIXME: Allow use of source disk, and maybe cause errors in read. */ ++ grub_dprintf ("luks2", "Source disk %s has an unknown size, " ++ "conservatively returning error\n", disk->name); ++ ret = grub_error (GRUB_ERR_BUG, "Unknown size of luks2 source device"); ++ goto err; ++ } ++ ++ cryptodisk = grub_zalloc (sizeof (*cryptodisk)); ++ if (!cryptodisk) ++ return NULL; ++ ++ ++ /* Try all keyslot */ ++ for (json_idx = 0; json_idx < size; json_idx++) ++ { ++ char indexstr[21]; /* log10(2^64) ~ 20, plus NUL character. */ ++ typeof (disk->total_sectors) max_crypt_sectors = 0; ++ ++ grub_errno = GRUB_ERR_NONE; ++ ret = luks2_get_keyslot (&keyslot, &digest, &segment, json, json_idx); ++ if (ret) ++ goto err; ++ if (grub_errno != GRUB_ERR_NONE) ++ grub_dprintf ("luks2", "Ignoring unhandled error %d from luks2_get_keyslot\n", grub_errno); ++ ++ if (keyslot.priority == 0) ++ { ++ grub_dprintf ("luks2", "Ignoring keyslot \"%" PRIuGRUB_UINT64_T "\" due to priority\n", keyslot.idx); ++ continue; ++ } ++ ++ grub_dprintf ("luks2", "Trying keyslot \"%" PRIuGRUB_UINT64_T "\"\n", keyslot.idx); ++ ++ /* Sector size should be one of 512, 1024, 2048, or 4096. */ ++ if (!(segment.sector_size == 512 || segment.sector_size == 1024 || ++ segment.sector_size == 2048 || segment.sector_size == 4096)) ++ { ++ grub_dprintf ("luks2", "Segment \"%" PRIuGRUB_UINT64_T "\" sector" ++ " size %" PRIuGRUB_UINT64_T " is not one of" ++ " 512, 1024, 2048, or 4096\n", ++ segment.idx, segment.sector_size); ++ continue; ++ } ++ ++ /* Set up disk according to keyslot's segment. */ ++ cryptodisk->offset_sectors = grub_divmod64 (segment.offset, segment.sector_size, NULL); ++ cryptodisk->log_sector_size = grub_log2ull (segment.sector_size); ++ /* Set to the source disk/partition size, which is the maximum we allow. */ ++ max_crypt_sectors = grub_disk_native_sectors (disk); ++ max_crypt_sectors = grub_convert_sector (max_crypt_sectors, GRUB_DISK_SECTOR_BITS, ++ cryptodisk->log_sector_size); ++ ++ if (max_crypt_sectors < cryptodisk->offset_sectors) ++ { ++ grub_dprintf ("luks2", "Segment \"%" PRIuGRUB_UINT64_T "\" has offset" ++ " %" PRIuGRUB_UINT64_T " which is greater than" ++ " source disk size %" PRIuGRUB_UINT64_T "," ++ " skipping\n", segment.idx, cryptodisk->offset_sectors, ++ max_crypt_sectors); ++ continue; ++ } ++ ++ if (grub_strcmp (segment.size, "dynamic") == 0) ++ cryptodisk->total_sectors = max_crypt_sectors - cryptodisk->offset_sectors; ++ else ++ { ++ grub_errno = GRUB_ERR_NONE; ++ ++ /* Convert segment.size to sectors, rounding up to nearest sector */ ++ cryptodisk->total_sectors = grub_strtoull (segment.size, NULL, 10); ++ ++ if (grub_errno == GRUB_ERR_NONE) ++ { ++ cryptodisk->total_sectors = ALIGN_UP (cryptodisk->total_sectors, ++ 1 << cryptodisk->log_sector_size); ++ cryptodisk->total_sectors >>= cryptodisk->log_sector_size; ++ } ++ else if (grub_errno == GRUB_ERR_BAD_NUMBER) ++ { ++ grub_dprintf ("luks2", "Segment \"%" PRIuGRUB_UINT64_T "\" size" ++ " \"%s\" is not a parsable number," ++ " skipping keyslot\n", ++ segment.idx, segment.size); ++ continue; ++ } ++ else if (grub_errno == GRUB_ERR_OUT_OF_RANGE) ++ { ++ /* ++ * There was an overflow in parsing segment.size, so disk must ++ * be very large or the string is incorrect. ++ * ++ * TODO: Allow reading of at least up max_crypt_sectors. Really, ++ * its very unlikely one would be booting from such a large drive ++ * anyway. Use another smaller LUKS2 boot device. ++ */ ++ grub_dprintf ("luks2", "Segment \"%" PRIuGRUB_UINT64_T "\" size" ++ " %s overflowed 64-bit unsigned integer," ++ " skipping keyslot\n", segment.idx, segment.size); ++ continue; ++ } ++ } ++ ++ if (cryptodisk->total_sectors == 0) ++ { ++ grub_dprintf ("luks2", "Segment \"%" PRIuGRUB_UINT64_T "\" has zero" ++ " sectors, skipping\n", segment.idx); ++ continue; ++ } ++ else if (max_crypt_sectors < (cryptodisk->offset_sectors + cryptodisk->total_sectors)) ++ { ++ grub_dprintf ("luks2", "Segment \"%" PRIuGRUB_UINT64_T "\" has last" ++ " data position greater than source disk size," ++ " the end of the crypto device will be" ++ " inaccessible\n", segment.idx); ++ ++ /* Allow decryption up to the end of the source disk. */ ++ cryptodisk->total_sectors = max_crypt_sectors - cryptodisk->offset_sectors; ++ } ++ ++ /* Set up disk hash. */ ++ if (keyslot.kdf.type == LUKS2_KDF_TYPE_PBKDF2) ++ { ++ hash = grub_crypto_lookup_md_by_name (keyslot.kdf.u.pbkdf2.hash); ++ if (!hash) ++ { ++ ret = grub_error (GRUB_ERR_FILE_NOT_FOUND, "Couldn't load %s hash", ++ keyslot.kdf.u.pbkdf2.hash); ++ goto err; ++ } ++ if (cryptodisk->hash) ++ { ++ if (grub_strcmp(hash->name, cryptodisk->hash->name)) { ++ ret = grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, "LUKS2 Module does not support using multiple SHA versions."); ++ goto err; ++ } ++ } else ++ cryptodisk->hash = hash; ++ } ++ } + + for (i = 0, j = 0; i < sizeof (header.uuid); i++) + if (header.uuid[i] != '-') +@@ -376,15 +553,39 @@ luks2_scan (grub_disk_t disk, grub_cryptomount_args_t cargs) + return NULL; + } + +- cryptodisk = grub_zalloc (sizeof (*cryptodisk)); +- if (!cryptodisk) +- return NULL; +- + COMPILE_TIME_ASSERT (sizeof (cryptodisk->uuid) >= sizeof (uuid)); + grub_memcpy (cryptodisk->uuid, uuid, sizeof (uuid)); + ++ hash = grub_crypto_lookup_md_by_name (digest.hash); ++ if (cryptodisk->hash) { ++ if (grub_strcmp(hash->name, cryptodisk->hash->name)) { ++ ret = grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, "LUKS2 Module does not support using multiple SHA versions."); ++ goto err; ++ } ++ } else ++ cryptodisk->hash = hash; ++ ++ /* Set up disk cipher. */ ++ grub_strncpy (cipher, segment.encryption, sizeof (cipher)); ++ ptr = grub_memchr (cipher, '-', grub_strlen (cipher)); ++ if (!ptr) { ++ ret = grub_error (GRUB_ERR_BAD_ARGUMENT, "Invalid encryption"); ++ goto err; ++ } ++ *ptr = '\0'; ++ ++ ret = grub_cryptodisk_setcipher (cryptodisk, cipher, ptr + 1); ++ if (ret) ++ goto err; ++ ++ + cryptodisk->modname = "luks2"; + return cryptodisk; ++err: ++ grub_free (json_header); ++ grub_json_free (json); ++ grub_errno = ret; ++ return NULL; + } + + static grub_err_t +diff --git a/grub-core/osdep/devmapper/getroot.c b/grub-core/osdep/devmapper/getroot.c +index 9ba5c9865..9ae1780c9 100644 +--- a/grub-core/osdep/devmapper/getroot.c ++++ b/grub-core/osdep/devmapper/getroot.c +@@ -141,7 +141,12 @@ grub_util_get_dm_abstraction (const char *os_dev) + if (strncmp (uuid, "CRYPT-LUKS1-", 12) == 0) + { + grub_free (uuid); +- return GRUB_DEV_ABSTRACTION_LUKS; ++ return GRUB_DEV_ABSTRACTION_LUKS1; ++ } ++ if (strncmp (uuid, "CRYPT-LUKS2-", 12) == 0) ++ { ++ grub_free (uuid); ++ return GRUB_DEV_ABSTRACTION_LUKS2; + } + + grub_free (uuid); +@@ -179,7 +184,7 @@ grub_util_pull_devmapper (const char *os_dev) + grub_util_pull_device (subdev); + } + } +- if (uuid && strncmp (uuid, "CRYPT-LUKS1-", sizeof ("CRYPT-LUKS1-") - 1) == 0 ++ if (uuid && (strncmp (uuid, "CRYPT-LUKS1-", sizeof ("CRYPT-LUKS1-") - 1) == 0 || strncmp (uuid, "CRYPT-LUKS2-", sizeof ("CRYPT-LUKS2-") - 1) == 0) + && lastsubdev) + { + char *grdev = grub_util_get_grub_dev (lastsubdev); +@@ -249,7 +254,8 @@ grub_util_get_devmapper_grub_dev (const char *os_dev) + return grub_dev; + } + +- case GRUB_DEV_ABSTRACTION_LUKS: ++ case GRUB_DEV_ABSTRACTION_LUKS1: ++ case GRUB_DEV_ABSTRACTION_LUKS2: + { + char *dash; + +diff --git a/include/grub/emu/getroot.h b/include/grub/emu/getroot.h +index 73fa2d34a..1a27faf28 100644 +--- a/include/grub/emu/getroot.h ++++ b/include/grub/emu/getroot.h +@@ -29,7 +29,8 @@ enum grub_dev_abstraction_types { + GRUB_DEV_ABSTRACTION_NONE, + GRUB_DEV_ABSTRACTION_LVM, + GRUB_DEV_ABSTRACTION_RAID, +- GRUB_DEV_ABSTRACTION_LUKS, ++ GRUB_DEV_ABSTRACTION_LUKS1, ++ GRUB_DEV_ABSTRACTION_LUKS2, + GRUB_DEV_ABSTRACTION_GELI, + }; + +diff --git a/util/getroot.c b/util/getroot.c +index a5eaa64fd..76d86c174 100644 +--- a/util/getroot.c ++++ b/util/getroot.c +@@ -100,7 +100,8 @@ grub_util_pull_device (const char *os_dev) + case GRUB_DEV_ABSTRACTION_LVM: + grub_util_pull_lvm_by_command (os_dev); + /* Fallthrough - in case that lvm-tools are unavailable. */ +- case GRUB_DEV_ABSTRACTION_LUKS: ++ case GRUB_DEV_ABSTRACTION_LUKS1: ++ case GRUB_DEV_ABSTRACTION_LUKS2: + grub_util_pull_devmapper (os_dev); + return; |