From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from list by lists.gnu.org with archive (Exim 4.90_1) id 1p19Zd-0005Iv-BH for mharc-grub-devel@gnu.org; Fri, 02 Dec 2022 12:11:41 -0500 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1p19Zc-0005Id-Hh for grub-devel@gnu.org; Fri, 02 Dec 2022 12:11:40 -0500 Received: from mail-4018.proton.ch ([185.70.40.18]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1p19ZW-00014T-KK for grub-devel@gnu.org; Fri, 02 Dec 2022 12:11:40 -0500 Date: Fri, 02 Dec 2022 17:11:23 +0000 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=fomin.one; s=protonmail2; t=1670001090; x=1670260290; bh=4CtV/N5ZZIyBRO1VBhOafuPsXU55NBKJzdEyn399Mc8=; h=Date:To:From:Subject:Message-ID:In-Reply-To:References: Feedback-ID:From:To:Cc:Date:Subject:Reply-To:Feedback-ID: Message-ID:BIMI-Selector; b=J3FF97b42CkHHF3k+1IxLhSb6duVsIkh1U544IrJoQQZogWxVexTKrEq0Z1u9sqBW Nv1utyzR4keZuT+fpjZ5svJbtmJzGuFABy/JzCghbjqG1Gf4mOzM5pgb/ZqyXp+uZa 6At0UO6t8hi9g1KhVIDycVJXXtEUnTm3/J0kTeQ6z0AU2+WkV2qoMejz/QTrG/FDw4 shg913R06FxbFCtUfBqzTtP9oNYM4L7HpESvYSyVHiynqHMJbftHB74N7l/xeJtEJo eNiCiKPInKT1zw5sM7zH91pS6nvCd9VP2bB8DxqVfrRm9m++DzAfsgTZxdQSaJRrmq 5CZWLlMvZxWBA== To: development@efficientek.com, "grub-devel@gnu.org" , "dkiper@net-space.pl" , "ps@pks.im" From: Maxim Fomin Subject: Re: [PATCH v8 1/1] plainmount: Support plain encryption mode Message-ID: <3fIZJQVSGi0Q_eyZ7CvJppLpelCcx9lgm1OeHzGjU2Va9mdeCH-J9TXdebbdgE7PN4s_qDesWKgbXHItgrnT6_HlhUvRt_wYtYEDgnmvjsY=@fomin.one> In-Reply-To: <20221201150046.093d61f4@crass-HP-ZBook-15-G2> References: <20221201150046.093d61f4@crass-HP-ZBook-15-G2> Feedback-ID: 10594471:user:proton MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: quoted-printable Received-SPF: pass client-ip=185.70.40.18; envelope-from=maxim@fomin.one; helo=mail-4018.proton.ch X-Spam_score_int: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, SPF_HELO_PASS=-0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: grub-devel@gnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: The development of GNU GRUB List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Fri, 02 Dec 2022 17:11:40 -0000 ------- Original Message ------- On Friday, December 2nd, 2022 at 0:00, Glenn Washburn wrote: >=20 >=20 > On Sat, 29 Oct 2022 17:40:42 +0000 > Maxim Fomin maxim@fomin.one wrote: >=20 > > From 2b1d2deb3f2416cbc3e7d25cbc4141a3078eaf68 Mon Sep 17 00:00:00 2001 > > From: Maxim Fomin maxim@fomin.one > > Date: Sat, 29 Oct 2022 18:18:58 +0100 > > Subject: [PATCH v8 1/1] plainmount: Support plain encryption mode > >=20 > > This patch adds support for plain encryption mode (plain dm-crypt) via > > new module/command named 'plainmount'. > >=20 > > Signed-off-by: Maxim Fomin maxim@fomin.one > >=20 > > Difference with v7: >=20 >=20 > Daniel pointed this out, but this isn't a well formed patch. I do very > much appreciate you adding the differences in as it made it easier to > look at this. And my suggestion was to use --interdiff or --range-diff > to the format-patch command, which would properly format things. It > looks like you just copy pasted the output of "git diff v7 v8". I will try to fix these issues in v9. > I'm now compiling this patch and found a few compile issues below. > You're compile testing this right? First versions of the patch were tested in pure grub src directory. Later I switched to directly making and installing GRUB package for my distro using its source script syntax. It seems this process was affected by environment options which hided these errors/warnings. I test the patch on my two old laptops - one with UEFI BIOS (x86_64-efi) and one is pre-UEFI (i386-pc). I was compiling i386-pc target too, because otherwise the second laptop was unbootable. During i386-pc compilation I noticed some warnings related to 'PRIuGRUB_XXX' macros which were absent during efi target compilation. I noticed that there are similar warnings in other modules and decided that there are issues with 'PRIuGRUB_XXX' macros at i386-pc platform at global level. In any case, these issues didn't cause compilation fail in my working environment because I would not be able to compile and boot pre-UEFI lap. Do you use -Werror?=20 P.S. Also thanks for suggested fixes. Best regards, Maxim Fomin > > diff --git a/docs/grub.texi b/docs/grub.texi > > index 377969984..34ca6b4f1 100644 > > --- a/docs/grub.texi > > +++ b/docs/grub.texi > > @@ -5138,13 +5138,13 @@ to generate password hashes. @xref{Security}. > >=20 > > Setup access to the encrypted device in plain mode. Offset of the > > encrypted -data at the device is specified in terms of 512 byte > > sectors with the blocklist +data at the device is specified in terms > > of 512 byte sectors using the blocklist syntax and loopback device. > > The following example shows how to specify 1MiB offset: > >=20 > > @example > > loopback node (hd0,gpt1)2048+ > > -plainmount node > > +plainmount node @var{...} > > @end example > >=20 > > The @command{plainmount} command can be used to open LUKS encrypted > > volume @@ -5155,13 +5155,14 @@ The keyfile path parameter has higher > > priority than the secret passphrase parameter and is specified with > > the option @option{-d}. Password data obtained from keyfiles is not > > hashed and is used directly as a cipher key. An optional offset of > > password data in the keyfile can be specified with the option > > -@option{-O} or directly with the option @option{-d} and GRUB > > blocklist syntax. +@option{-O} or directly with the option > > @option{-d} and GRUB blocklist syntax, +if the keyfile data can be > > accessed from a device and is 512 byte aligned. The following example > > shows both methods to specify password data in the keyfile at offset > > 1MiB: > >=20 > > @example > > -plainmount -d (hd0,gpt1)2048+ > > -plainmount -d (hd0,gpt1)+ -O 1048576 > > +plainmount -d (hd0,gpt1)2048+ @var{...} > > +plainmount -d (hd0,gpt1)+ -O 1048576 @var{...} > > @end example > >=20 > > If no keyfile is specified then the password is set to the string > > specified diff --git a/grub-core/disk/plainmount.c > > b/grub-core/disk/plainmount.c index 656c5d09f..85ada25bc 100644 > > --- a/grub-core/disk/plainmount.c > > +++ b/grub-core/disk/plainmount.c > > @@ -146,8 +146,12 @@ plainmount_configure_password (grub_cryptodisk_t > > dev, const char *hash, dev->hash =3D grub_crypto_lookup_md_by_name > > (hash); len =3D dev->hash->mdlen; > >=20 > > - alloc_size =3D password_size >=3D key_size ? password_size : key_size= ; > > - p =3D grub_zalloc (alloc_size + (alloc_size / len)); > > + alloc_size =3D grub_max (password_size, key_size); > > + /* > > + * Allocate buffer for the password and for an added prefix > > character > > + * for each hash round ('alloc_size' may not be a multiple of > > 'len'). > > + */ > > + p =3D grub_zalloc (alloc_size + (alloc_size / len) + 1); > > derived_hash =3D grub_zalloc (GRUB_CRYPTODISK_MAX_KEYLEN * 2); > > if (p =3D=3D NULL || derived_hash =3D=3D NULL) > > { > > @@ -170,9 +174,10 @@ plainmount_configure_password (grub_cryptodisk_t > > dev, const char *hash, if (len > size) > > len =3D size; > >=20 > > - grub_crypto_hash (dev->hash, dh, p, password_size); > > + grub_crypto_hash (dev->hash, dh, p, password_size + round); > > } > > - grub_memcpy (key_data, derived_hash, GRUB_CRYPTODISK_MAX_KEYLEN * > > 2); > > + grub_memcpy (key_data, derived_hash, key_size); > > + > > exit: > > grub_free (p); > > grub_free (derived_hash); > > --- > > docs/grub.texi | 81 +++++++ > > grub-core/Makefile.core.def | 5 + > > grub-core/disk/plainmount.c | 462 > > ++++++++++++++++++++++++++++++++++++ 3 files changed, 548 > > insertions(+) create mode 100644 grub-core/disk/plainmount.c > >=20 > > diff --git a/docs/grub.texi b/docs/grub.texi > > index 2d6cd8358..34ca6b4f1 100644 > > --- a/docs/grub.texi > > +++ b/docs/grub.texi > > @@ -4271,6 +4271,7 @@ you forget a command, you can run the command > > @command{help} > > * parttool:: Modify partition table entries > > * password:: Set a clear-text password > > * password_pbkdf2:: Set a hashed password > > +* plainmount:: Open device encrypted in plain mode > > * play:: Play a tune > > * probe:: Retrieve device info > > * rdmsr:: Read values from model-specific > > registers @@ -4558,6 +4559,14 @@ function is supported, as Argon2 is > > not yet supported. > > Also, note that, unlike filesystem UUIDs, UUIDs for encrypted > > devices must be specified without dash separators. > > + > > +Successfully decrypted disks are named as (cryptoX) and have > > increasing numeration +suffix for each new decrypted disk. If the > > encrypted disk hosts some higher level +of abstraction (like LVM2 or > > MDRAID) it will be created under a separate device +namespace in > > addition to the cryptodisk namespace. + > > +Support for plain encryption mode (plain dm-crypt) is provided via > > separate +@command{@pxref{plainmount}} command. > > @end deffn > >=20 > > @node cutmem > > @@ -5120,6 +5129,78 @@ to generate password hashes. @xref{Security}. > > @end deffn > >=20 > > +@node plainmount > > +@subsection plainmount > > + > > +@deffn Command plainmount device @option{-c} cipher @option{-s} key > > size [@option{-h} hash] +[@option{-S} sector size] [@option{-p} > > password] [@option{-u} uuid] +[[@option{-d} keyfile] [@option{-O} > > keyfile offset]] + > > + > > +Setup access to the encrypted device in plain mode. Offset of the > > encrypted +data at the device is specified in terms of 512 byte > > sectors using the blocklist +syntax and loopback device. The > > following example shows how to specify 1MiB +offset: > > + > > +@example > > +loopback node (hd0,gpt1)2048+ > > +plainmount node @var{...} > > +@end example > > + > > +The @command{plainmount} command can be used to open LUKS encrypted > > volume +if its master key and parameters (key size, cipher, offset, > > etc) are known. + > > +There are two ways to specify a password: a keyfile and a secret > > passphrase. +The keyfile path parameter has higher priority than the > > secret passphrase +parameter and is specified with the option > > @option{-d}. Password data obtained +from keyfiles is not hashed and > > is used directly as a cipher key. An optional +offset of password > > data in the keyfile can be specified with the option +@option{-O} or > > directly with the option @option{-d} and GRUB blocklist syntax, +if > > the keyfile data can be accessed from a device and is 512 byte > > aligned. +The following example shows both methods to specify > > password data in the +keyfile at offset 1MiB: + > > +@example > > +plainmount -d (hd0,gpt1)2048+ @var{...} > > +plainmount -d (hd0,gpt1)+ -O 1048576 @var{...} > > +@end example > > + > > +If no keyfile is specified then the password is set to the string > > specified +by option @option{-p} or is requested interactively from > > the console. In both +cases the provided password is hashed with the > > algorithm specified by the +option @option{-h}. This option is > > mandatory if no keyfile is specified, but +it can be set to > > @samp{plain} which means that no hashing is done and such +password > > is used directly as a key. + > > +Cipher @option{-c} and keysize @option{-s} options specify the > > cipher algorithm +and the key size respectively and are mandatory > > options. Cipher must be specified +with the mode separated by a dash > > (for example, @samp{aes-xts-plain64}). Key size +option @option{-s} > > is the key size of the cipher in bits, not to be confused with +the > > offset of the key data in a keyfile specified with the @option{-O} > > option. It +must not exceed 1024 bits, so a 32 byte key would be > > specified as 256 bits + +The optional parameter @option{-S} specifies > > encrypted device sector size. It +must be at least 512 bytes long > > (default value) and a power of 2. @footnote{Current +implementation > > of cryptsetup supports only 512/1024/2048/4096 byte sectors}. +Disk > > sector size is configured when creating the encrypted volume. > > Attempting +to decrypt volumes with a different sector size than it > > was created with will +not result in an error, but will decrypt to > > random bytes and thus prevent +accessing the volume (in some cases > > the filesystem driver can detect the presence +of a filesystem, but > > nevertheless will refuse to mount it). + +By default new plainmount > > devices will be given a UUID starting with > > +'109fea84-a6b7-34a8-4bd1-1c506305a401' where the last digits are > > incremented +by one for each plainmounted device beyond the first up > > to 2^10 devices. + +All encryption arguments (cipher, hash, key size, > > disk offset and disk sector +size) must match the parameters used to > > create the volume. If any of them does +not match the actual > > arguments used during the initial encryption, plainmount +will create > > virtual device with the garbage data and GRUB will report unknown > > +filesystem for such device. Writing data to such virtual device will > > result in +the data loss if the underlying partition contained > > desired data. +@end deffn + > > + > > @node play > > @subsection play > >=20 > > diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def > > index 98714c68d..f4153608c 100644 > > --- a/grub-core/Makefile.core.def > > +++ b/grub-core/Makefile.core.def > > @@ -1184,6 +1184,11 @@ module =3D { > > common =3D disk/cryptodisk.c; > > }; > >=20 > > +module =3D { > > + name =3D plainmount; > > + common =3D disk/plainmount.c; > > +}; > > + > > module =3D { > > name =3D json; > > common =3D lib/json/json.c; > > diff --git a/grub-core/disk/plainmount.c b/grub-core/disk/plainmount.c > > new file mode 100644 > > index 000000000..85ada25bc > > --- /dev/null > > +++ b/grub-core/disk/plainmount.c > > @@ -0,0 +1,462 @@ > > +/* > > + * GRUB -- GRand Unified Bootloader > > + * Copyright (C) 2022 Free Software Foundation, 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 http://www.gnu.org/licenses/. > > + / > > + > > +/ plaimount.c - Open device encrypted in plain mode. / > > + > > +#include > > +#include > > +#include > > +#include > > +#include > > +#include > > + > > + > > +GRUB_MOD_LICENSE ("GPLv3+"); > > + > > +#define PLAINMOUNT_DEFAULT_SECTOR_SIZE 512 > > +#define PLAINMOUNT_DEFAULT_UUID > > "109fea84-a6b7-34a8-4bd1-1c506305a400" + > > + > > +enum PLAINMOUNT_OPTION > > + { > > + OPTION_HASH, > > + OPTION_CIPHER, > > + OPTION_KEY_SIZE, > > + OPTION_SECTOR_SIZE, > > + OPTION_PASSWORD, > > + OPTION_KEYFILE, > > + OPTION_KEYFILE_OFFSET, > > + OPTION_UUID > > + }; > > + > > + > > +static const struct grub_arg_option options[] =3D > > + { > > + / TRANSLATORS: It's still restricted to this module only. / > > + {"hash", 'h', 0, N_("Password hash"), 0, ARG_TYPE_STRING}, > > + {"cipher", 'c', 0, N_("Password cipher"), 0, ARG_TYPE_STRING}, > > + {"key-size", 's', 0, N_("Key size (in bits)"), 0, ARG_TYPE_INT}, > > + {"sector-size", 'S', 0, N_("Device sector size"), 0, > > ARG_TYPE_INT}, > > + {"password", 'p', 0, N_("Password (key)"), 0, ARG_TYPE_STRING}, > > + {"keyfile", 'd', 0, N_("Keyfile path"), 0, ARG_TYPE_STRING}, > > + {"keyfile-offset", 'O', 0, N_("Keyfile offset"), 0, > > ARG_TYPE_INT}, > > + {"uuid", 'u', 0, N_("Set device UUID"), 0, ARG_TYPE_STRING}, > > + {0, 0, 0, 0, 0, 0} > > + }; > > + > > + > > +/ Cryptodisk setkey() function wrapper */ > > +static grub_err_t > > +plainmount_setkey (grub_cryptodisk_t dev, grub_uint8_t key, > > + grub_size_t size) > > +{ > > + gcry_err_code_t code =3D grub_cryptodisk_setkey (dev, key, size); > > + if (code !=3D GPG_ERR_NO_ERROR) > > + { > > + grub_dprintf ("plainmount", "failed to set cipher key with > > code: %d\n", code); > > + return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("cannot set > > specified key")); > > + } > > + return GRUB_ERR_NONE; > > +} > > + > > + > > +/ Configure cryptodisk uuid */ > > +static void plainmount_set_uuid (grub_cryptodisk_t dev, const char > > user_uuid) +{ > > + grub_size_t pos =3D 0; > > + > > + / Size of user_uuid is checked in main func / > > + if (user_uuid !=3D NULL) > > + grub_memcpy (dev->uuid, user_uuid, grub_strlen (user_uuid)); > > + else > > + { > > + / > > + * Set default UUID. Last digits start from 1 and are > > incremented for > > + * each new plainmount device by snprintf(). > > + / > > + grub_snprintf (dev->uuid, sizeof (dev->uuid)-1, "%36lx", > > dev->id+1); > > + while (dev->uuid[++pos] =3D=3D ' '); > > + grub_memcpy (dev->uuid, PLAINMOUNT_DEFAULT_UUID, pos); > > + } > > + COMPILE_TIME_ASSERT (sizeof (dev->uuid) >=3D sizeof > > (PLAINMOUNT_DEFAULT_UUID)); +} > > + > > + > > +/ Configure cryptodevice sector size (-S option) / > > +static grub_err_t > > +plainmount_configure_sectors (grub_cryptodisk_t dev, grub_disk_t > > disk, > > + grub_size_t sector_size) > > +{ > > + dev->total_sectors =3D grub_disk_native_sectors (disk); > > + if (dev->total_sectors =3D=3D GRUB_DISK_SIZE_UNKNOWN) > > + return grub_error (GRUB_ERR_BAD_DEVICE, N_("cannot determine > > disk %s size"), > > + disk->name); > > + > > + / Convert size to sectors */ > > + dev->log_sector_size =3D grub_log2ull (sector_size); > > + dev->total_sectors =3D grub_convert_sector (dev->total_sectors, > > + GRUB_DISK_SECTOR_BITS, > > + dev->log_sector_size); > > + if (dev->total_sectors =3D=3D 0) > > + return grub_error (GRUB_ERR_BAD_DEVICE, > > + N_("cannot set specified sector size on disk > > %s"), > > + disk->name); > > + > > + grub_dprintf ("plainmount", "log_sector_size=3D%d, total_sectors=3D%" > > + PRIuGRUB_SIZE"\n", dev->log_sector_size, > > dev->total_sectors); >=20 >=20 > s/PRIuGRUB_SIZE/PRIuGRUB_UINT64_T/ >=20 > This compiles fine on x86_64 as is, but fails to compile on i386. >=20 > > + return GRUB_ERR_NONE; > > +} > > + > > + > > +/* Hashes a password into a key and stores it with the cipher. */ > > +static grub_err_t > > +plainmount_configure_password (grub_cryptodisk_t dev, const char > > *hash, > > + grub_uint8_t *key_data, grub_size_t > > key_size, > > + grub_size_t password_size) > > +{ > > + grub_uint8_t *derived_hash, dh; > > + char p; > > + unsigned int round, i, len, size; > > + grub_size_t alloc_size; > > + grub_err_t err =3D GRUB_ERR_NONE; > > + > > + / Support none (plain) hash / > > + if (grub_strcmp (hash, "plain") =3D=3D 0) > > + { > > + dev->hash =3D NULL; > > + return err; > > + } > > + > > + / Hash argument was checked at main func / > > + dev->hash =3D grub_crypto_lookup_md_by_name (hash); > > + len =3D dev->hash->mdlen; > > + > > + alloc_size =3D grub_max (password_size, key_size); > > + / > > + * Allocate buffer for the password and for an added prefix > > character > > + * for each hash round ('alloc_size' may not be a multiple of > > 'len'). > > + / > > + p =3D grub_zalloc (alloc_size + (alloc_size / len) + 1); > > + derived_hash =3D grub_zalloc (GRUB_CRYPTODISK_MAX_KEYLEN * 2); > > + if (p =3D=3D NULL || derived_hash =3D=3D NULL) > > + { > > + err =3D grub_error (GRUB_ERR_OUT_OF_MEMORY, "out of memory"); > > + goto exit; > > + } > > + dh =3D derived_hash; > > + > > + / > > + * Hash password. Adapted from cryptsetup. > > + * > > https://gitlab.com/cryptsetup/cryptsetup/-/blob/main/lib/crypt_plain.c > > + / > > + for (round =3D 0, size =3D alloc_size; size; round++, dh +=3D len, si= ze > > -=3D len) > > + { > > + for (i =3D 0; i < round; i++) > > + p[i] =3D 'A'; > > + > > + grub_memcpy (p + i, (char) key_data, password_size); > > + > > + if (len > size) > > + len =3D size; > > + > > + grub_crypto_hash (dev->hash, dh, p, password_size + round); > > + } > > + grub_memcpy (key_data, derived_hash, key_size); > > + > > +exit: > > + grub_free (p); > > + grub_free (derived_hash); > > + return err; > > +} > > + > > + > > +/ Read key material from keyfile */ > > +static grub_err_t > > +plainmount_configure_keyfile (char *keyfile, grub_uint8_t *key_data, > > + grub_size_t key_size, grub_size_t > > keyfile_offset) +{ > > + grub_file_t g_keyfile =3D grub_file_open (keyfile, > > GRUB_FILE_TYPE_NONE); > > + if (g_keyfile =3D=3D NULL) > > + return grub_error (GRUB_ERR_FILE_NOT_FOUND, N_("cannot open > > keyfile %s"), > > + keyfile); > > + > > + if (grub_file_seek (g_keyfile, keyfile_offset) =3D=3D (grub_off_t)-1) > > + return grub_error (GRUB_ERR_FILE_READ_ERROR, > > + N_("cannot seek keyfile at offset > > %"PRIuGRUB_SIZE), > > + keyfile_offset); > > + > > + if (key_size > (g_keyfile->size - keyfile_offset)) > > + return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("Specified key size > > (%" > > + PRIuGRUB_SIZE") is too small for keyfile size > > (%" > > + PRIuGRUB_SIZE") and offset > > (%"PRIuGRUB_SIZE")"), >=20 >=20 > Also, this compiles fine on x86_64 as is, but fails to compile on i386. >=20 > The format code for g_keyfile->size should be PRIuGRUB_UINT64_T. >=20 > > + key_size, g_keyfile->size, keyfile_offset); > > + > > + if (grub_file_read (g_keyfile, key_data, key_size) !=3D > > (grub_ssize_t) key_size) > > + return grub_error (GRUB_ERR_FILE_READ_ERROR, N_("error reading > > key file")); > > + return GRUB_ERR_NONE; > > +} > > + > > + > > +/* Plainmount command entry point */ > > +static grub_err_t > > +grub_cmd_plainmount (grub_extcmd_context_t ctxt, int argc, char > > **args) +{ > > + struct grub_arg_list *state =3D ctxt->state; > > + grub_cryptodisk_t dev =3D NULL; > > + grub_disk_t disk =3D NULL; > > + const gcry_md_spec_t *gcry_hash; > > + char *diskname, *disklast =3D NULL, *cipher, *mode, *hash, *keyfile, > > *uuid; > > + grub_size_t len, key_size, sector_size, keyfile_offset =3D 0, > > password_size =3D 0; > > + grub_err_t err; > > + const char *p; > > + grub_uint8_t key_data; > > + > > + if (argc < 1) > > + return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("device name > > required")); + > > + / Check whether required arguments are specified / > > + if (!state[OPTION_CIPHER].set || !state[OPTION_KEY_SIZE].set) > > + return grub_error (GRUB_ERR_BAD_ARGUMENT, "cipher and key size > > must be set"); > > + if (!state[OPTION_HASH].set && !state[OPTION_KEYFILE].set) > > + return grub_error (GRUB_ERR_BAD_ARGUMENT, "hash algorithm must > > be set"); + > > + / Check hash / > > + if (!state[OPTION_KEYFILE].set) > > + { > > + gcry_hash =3D grub_crypto_lookup_md_by_name > > (state[OPTION_HASH].arg); > > + if (!gcry_hash) > > + return grub_error (GRUB_ERR_FILE_NOT_FOUND, N_("couldn't load > > hash %s"), > > + state[OPTION_HASH].arg); > > + > > + if (gcry_hash->mdlen > GRUB_CRYPTODISK_MAX_KEYLEN) > > + return grub_error (GRUB_ERR_BAD_ARGUMENT, > > + N_("hash length %"PRIuGRUB_SIZE" exceeds > > maximum %d bits"), > > + gcry_hash->mdlen * GRUB_CHAR_BIT, > > + GRUB_CRYPTODISK_MAX_KEYLEN * GRUB_CHAR_BIT); > > + } > > + > > + / Check cipher mode / > > + if (!grub_strchr (state[OPTION_CIPHER].arg,'-')) > > + return grub_error (GRUB_ERR_BAD_ARGUMENT, > > + N_("invalid cipher mode, must be of format > > cipher-mode")); + > > + / Check password size / > > + if (state[OPTION_PASSWORD].set && grub_strlen > > (state[OPTION_PASSWORD].arg) > > > + > > GRUB_CRYPTODISK_MAX_PASSPHRASE) > > + return grub_error (GRUB_ERR_BAD_ARGUMENT, > > + N_("password exceeds maximium size")); > > + > > + / Check uuid length */ > > + if (state[OPTION_UUID].set && grub_strlen (state[OPTION_UUID].arg) > >=20 > > + sizeof (PLAINMOUNT_DEFAULT_UUID)) > > + return grub_error (GRUB_ERR_BAD_ARGUMENT, > > + N_("specified UUID exceeds maximum size")); > > + > > + /* Parse plainmount arguments */ > > + grub_errno =3D GRUB_ERR_NONE; > > + keyfile_offset =3D state[OPTION_KEYFILE_OFFSET].set ? > > + grub_strtoull (state[OPTION_KEYFILE_OFFSET].arg, > > &p, 0) : 0; > > + if (state[OPTION_KEYFILE_OFFSET].set && > > + (state[OPTION_KEYFILE_OFFSET].arg[0] =3D=3D '\0' || *p !=3D '\0' || > > + grub_errno !=3D GRUB_ERR_NONE)) > > + return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("unrecognized > > keyfile offset")); + > > + sector_size =3D state[OPTION_SECTOR_SIZE].set ? > > + grub_strtoull (state[OPTION_SECTOR_SIZE].arg, &p, 0) > > : > > + PLAINMOUNT_DEFAULT_SECTOR_SIZE; > > + if (state[OPTION_SECTOR_SIZE].set && > > (state[OPTION_SECTOR_SIZE].arg[0] =3D=3D '\0' || > > + p !=3D '\0' || grub_errno !=3D > > GRUB_ERR_NONE)) > > + return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("unrecognized > > sector size")); + > > + / Check key size */ > > + key_size =3D grub_strtoull (state[OPTION_KEY_SIZE].arg, &p, 0); > > + if (state[OPTION_KEY_SIZE].arg[0] =3D=3D '\0' || p !=3D '\0' || > > + grub_errno !=3D GRUB_ERR_NONE) > > + return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("unrecognized key > > size")); > > + if ((key_size % GRUB_CHAR_BIT) !=3D 0) > > + return grub_error (GRUB_ERR_BAD_ARGUMENT, > > + N_("key size is not multiple of %d bits"), > > GRUB_CHAR_BIT); > > + key_size =3D key_size / GRUB_CHAR_BIT; > > + if (key_size > GRUB_CRYPTODISK_MAX_KEYLEN) > > + return grub_error (GRUB_ERR_BAD_ARGUMENT, > > + N_("key size %"PRIuGRUB_SIZE" exceeds maximum > > %d bits"), > > + key_size * GRUB_CHAR_BIT, > > + GRUB_CRYPTODISK_MAX_KEYLEN * GRUB_CHAR_BIT); > > + > > + / Check disk sector size / > > + if (sector_size < GRUB_DISK_SECTOR_SIZE) > > + return grub_error (GRUB_ERR_BAD_ARGUMENT, > > + N_("sector size -S must be at least %d"), > > + GRUB_DISK_SECTOR_SIZE); > > + if ((sector_size & (sector_size - 1)) !=3D 0) > > + return grub_error (GRUB_ERR_BAD_ARGUMENT, > > + N_("sector size -S %"PRIuGRUB_SIZE" is not > > power of 2"), > > + sector_size); > > + > > + / Allocate all stuff here */ > > + hash =3D state[OPTION_HASH].set ? grub_strdup > > (state[OPTION_HASH].arg) : NULL; > > + cipher =3D grub_strdup (state[OPTION_CIPHER].arg); > > + keyfile =3D state[OPTION_KEYFILE].set ? > > + grub_strdup (state[OPTION_KEYFILE].arg) : NULL; > > + dev =3D grub_zalloc (sizeof dev); > > + key_data =3D grub_zalloc (GRUB_CRYPTODISK_MAX_PASSPHRASE); > > + uuid =3D state[OPTION_UUID].set ? grub_strdup > > (state[OPTION_UUID].arg) : NULL; > > + if ((hash =3D=3D NULL && state[OPTION_HASH].set) || cipher =3D=3D NUL= L || > > dev =3D=3D NULL || > > + (keyfile =3D=3D NULL && state[OPTION_KEYFILE].set) || key_data =3D=3D > > NULL || > > + (uuid =3D=3D NULL && state[OPTION_UUID].set)) > > + { > > + err =3D grub_error (GRUB_ERR_OUT_OF_MEMORY, "out of memory"); > > + goto exit; > > + } > > + > > + / Copy user password from -p option / > > + if (state[OPTION_PASSWORD].set) > > + { > > + / > > + * Password from the '-p' option is limited to C-string. > > + * Arbitrary data keys are supported via keyfiles. > > + / > > + password_size =3D grub_strlen (state[OPTION_PASSWORD].arg); > > + grub_memcpy (key_data, state[OPTION_PASSWORD].arg, > > password_size); > > + } > > + > > + / Copy user UUID from -u option / > > + if (state[OPTION_UUID].set) > > + grub_memcpy (uuid, state[OPTION_UUID].arg, > > + grub_strlen (state[OPTION_UUID].arg)); > > + > > + / Set cipher mode (tested above) */ > > + mode =3D grub_strchr (cipher,'-'); > > + mode++ =3D '\0'; > > + > > + / Check cipher / > > + if (grub_cryptodisk_setcipher (dev, cipher, mode) !=3D GRUB_ERR_NONE) > > + { > > + err =3D grub_error (GRUB_ERR_BAD_ARGUMENT, N_("invalid cipher > > %s"), cipher); > > + goto exit; > > + } > > + > > + / Open SOURCE disk */ > > + diskname =3D args[0]; > > + len =3D grub_strlen (diskname); > > + if (len && diskname[0] =3D=3D '(' && diskname[len - 1] =3D=3D ')') > > + { > > + disklast =3D &diskname[len - 1]; > > + *disklast =3D '\0'; > > + diskname++; > > + } > > + disk =3D grub_disk_open (diskname); > > + if (disk =3D=3D NULL) > > + { > > + if (disklast) > > + disklast =3D ')'; > > + err =3D grub_error (GRUB_ERR_BAD_ARGUMENT, N_("cannot open disk > > %s"), diskname); > > + goto exit; > > + } > > + > > + / Get password from console */ > > + if (!state[OPTION_KEYFILE].set && key_data[0] =3D=3D '\0') > > + { > > + char part =3D grub_partition_get_name (disk->partition); > > + grub_printf_ (N_("Enter passphrase for %s%s%s: "), disk->name, > > + disk->partition !=3D NULL ? "," : "", > > + part !=3D NULL ? part : N_("UNKNOWN")); > > + grub_free (part); > > + > > + if (!grub_password_get ((char)key_data, > > GRUB_CRYPTODISK_MAX_PASSPHRASE-1)) >=20 >=20 > Space between cast and key_data. >=20 > > + { > > + err =3D grub_error (GRUB_ERR_BAD_ARGUMENT, N_("error reading > > password")); > > + goto exit; > > + } > > + /* > > + * Password from interactive console is limited to C-string. > > + * Arbitrary data keys are supported via keyfiles. > > + */ > > + password_size =3D grub_strlen (key_data); >=20 >=20 > This caused x86_64 to fail to compile with sign mismatch. Should > probably cast to char * as above. >=20 > Glenn >=20 > > + } > > + > > + /* Warn if hash and keyfile are both provided / > > + if (state[OPTION_KEYFILE].set && state[OPTION_HASH].arg) > > + grub_printf_ (N_("warning: hash is ignored if keyfile is > > specified\n")); + > > + / Warn if -p option is specified with keyfile / > > + if (state[OPTION_PASSWORD].set && state[OPTION_KEYFILE].set) > > + grub_printf_ (N_("warning: password specified with -p option " > > + "is ignored if keyfile is provided\n")); > > + > > + / Warn of -O is provided without keyfile / > > + if (state[OPTION_KEYFILE_OFFSET].set && !state[OPTION_KEYFILE].set) > > + grub_printf_ (N_("warning: keyfile offset option -O " > > + "specified without keyfile option -d\n")); > > + > > + grub_dprintf ("plainmount", "parameters: cipher=3D%s, hash=3D%s, > > key_size=3D%" > > + PRIuGRUB_SIZE", keyfile=3D%s, keyfile > > offset=3D%"PRIuGRUB_SIZE"\n", > > + cipher, hash, key_size, keyfile, keyfile_offset); > > + > > + err =3D plainmount_configure_sectors (dev, disk, sector_size); > > + if (err !=3D GRUB_ERR_NONE) > > + goto exit; > > + > > + / Configure keyfile or password */ > > + if (state[OPTION_KEYFILE].set) > > + err =3D plainmount_configure_keyfile (keyfile, key_data, key_size, > > keyfile_offset); > > + else > > + err =3D plainmount_configure_password (dev, hash, key_data, > > key_size, password_size); > > + if (err !=3D GRUB_ERR_NONE) > > + goto exit; > > + > > + err =3D plainmount_setkey (dev, key_data, key_size); > > + if (err !=3D GRUB_ERR_NONE) > > + goto exit; > > + > > + err =3D grub_cryptodisk_insert (dev, diskname, disk); > > + if (err !=3D GRUB_ERR_NONE) > > + goto exit; > > + > > + dev->modname =3D "plainmount"; > > + dev->source_disk =3D disk; > > + plainmount_set_uuid (dev, uuid); > > + > > +exit: > > + grub_free (hash); > > + grub_free (cipher); > > + grub_free (keyfile); > > + grub_free (key_data); > > + grub_free (uuid); > > + if (err !=3D GRUB_ERR_NONE && disk) > > + grub_disk_close (disk); > > + if (err !=3D GRUB_ERR_NONE && dev) > > + grub_free (dev); > > + return err; > > +} > > + > > +static grub_extcmd_t cmd; > > +GRUB_MOD_INIT (plainmount) > > +{ > > + cmd =3D grub_register_extcmd ("plainmount", grub_cmd_plainmount, 0, > > + N_("-c cipher -s key-size [-h hash] > > [-S sector-size]" > > + " [-o offset] [-p password] [-u uuid] " > > + " [[-d keyfile] [-O keyfile offset]] > > "), > > + N_("Open partition encrypted in plain > > mode."), > > + options); > > +} > > + > > +GRUB_MOD_FINI (plainmount) > > +{ > > + grub_unregister_extcmd (cmd); > > +}