[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[PATCH v10] plainmount: Support plain encryption mode
From: |
Maxim Fomin |
Subject: |
[PATCH v10] plainmount: Support plain encryption mode |
Date: |
Wed, 28 Dec 2022 17:20:00 +0000 |
>From e7f54a0b78353c01bf4c966f871b3e3590222743 Mon Sep 17 00:00:00 2001
From: Maxim Fomin <maxim@fomin.one>
Date: Wed, 28 Dec 2022 13:19:36 +0000
Subject: [PATCH v10] plainmount: Support plain encryption mode
This patch adds support for plain encryption mode (plain dm-crypt) via
new module/command named 'plainmount'.
Signed-off-by: Maxim Fomin <maxim@fomin.one>
---
Interdiff against v9:
diff --git a/grub-core/disk/plainmount.c b/grub-core/disk/plainmount.c
index eabedf4c3..47e64805f 100644
--- a/grub-core/disk/plainmount.c
+++ b/grub-core/disk/plainmount.c
@@ -326,7 +326,7 @@ grub_cmd_plainmount (grub_extcmd_context_t ctxt, int
argc, char **args)
* Arbitrary data keys are supported via keyfiles.
*/
password_size = grub_strlen (state[OPTION_PASSWORD].arg);
- grub_memcpy (key_data, state[OPTION_PASSWORD].arg, password_size);
+ grub_strcpy ((char*) key_data, state[OPTION_PASSWORD].arg);
}
/* Set cipher mode (tested above) */
@@ -334,9 +334,16 @@ grub_cmd_plainmount (grub_extcmd_context_t ctxt, int
argc, char **args)
*mode++ = '\0';
/* Check cipher */
- if (grub_cryptodisk_setcipher (dev, cipher, mode) != GRUB_ERR_NONE)
+ err = grub_cryptodisk_setcipher (dev, cipher, mode);
+ if (err != GRUB_ERR_NONE)
{
- err = grub_error (GRUB_ERR_BAD_ARGUMENT, N_("invalid cipher %s"),
cipher);
+ if (err == GRUB_ERR_FILE_NOT_FOUND)
+ err = grub_error (GRUB_ERR_BAD_ARGUMENT, N_("invalid cipher %s"),
cipher);
+ else if (err == GRUB_ERR_BAD_ARGUMENT)
+ err = grub_error (GRUB_ERR_BAD_ARGUMENT, N_("invalid mode %s"),
mode);
+ else
+ err = grub_error (GRUB_ERR_BAD_ARGUMENT, N_("invalid cipher %s or
mode %s"),
+ cipher, mode);
goto fail;
}
diff --git a/grub-core/fs/affs.c b/grub-core/fs/affs.c
index 631d3d58a..ed606b3f1 100644
--- a/grub-core/fs/affs.c
+++ b/grub-core/fs/affs.c
@@ -321,7 +321,6 @@ static int
grub_affs_create_node (grub_fshelp_node_t dir,
grub_fshelp_iterate_dir_hook_t hook, void *hook_data,
struct grub_fshelp_node **node,
- grub_uint32_t **hashtable,
grub_uint32_t block, const struct grub_affs_file *fil)
{
struct grub_affs_data *data = dir->data;
@@ -332,10 +331,7 @@ grub_affs_create_node (grub_fshelp_node_t dir,
*node = grub_zalloc (sizeof (**node));
if (!*node)
- {
- grub_free (*hashtable);
- return 1;
- }
+ return 1;
(*node)->data = data;
(*node)->block = block;
@@ -395,7 +391,6 @@ grub_affs_create_node (grub_fshelp_node_t dir,
if (hook ((char *) name_u8, type, *node, hook_data))
{
- grub_free (*hashtable);
*node = 0;
return 1;
}
@@ -460,11 +455,11 @@ grub_affs_iterate_dir (grub_fshelp_node_t dir,
if (grub_errno)
goto fail;
- if (grub_affs_create_node (dir, hook, hook_data, &node, &hashtable,
- next, &file))
+ if (grub_affs_create_node (dir, hook, hook_data, &node, next, &file))
{
/* Node has been replaced in function. */
grub_free (orig_node);
+ grub_free (hashtable);
return 1;
}
diff --git a/grub-core/fs/bfs.c b/grub-core/fs/bfs.c
index a75876010..07cb3e3ac 100644
--- a/grub-core/fs/bfs.c
+++ b/grub-core/fs/bfs.c
@@ -416,6 +416,8 @@ read_bfs_file (grub_disk_t disk,
len -= read_size;
buf = (char *) buf + read_size;
}
+ grub_free (l1_entries);
+ grub_free (l2_entries);
return GRUB_ERR_NONE;
}
}
diff --git a/grub-core/fs/btrfs.c b/grub-core/fs/btrfs.c
index ec72f7be3..19bff4610 100644
--- a/grub-core/fs/btrfs.c
+++ b/grub-core/fs/btrfs.c
@@ -1982,7 +1982,12 @@ find_path (struct grub_btrfs_data *data,
{
err = get_root (data, key, tree, type);
if (err)
- return err;
+ {
+ grub_free (direl);
+ grub_free (path_alloc);
+ grub_free (origpath);
+ return err;
+ }
}
continue;
}
diff --git a/grub-core/fs/hfsplus.c b/grub-core/fs/hfsplus.c
index 6337cbfcb..11393ca34 100644
--- a/grub-core/fs/hfsplus.c
+++ b/grub-core/fs/hfsplus.c
@@ -652,7 +652,10 @@ grub_hfsplus_btree_search (struct grub_hfsplus_btree
*btree,
+ 2);
if ((char *) pointer > node + btree->nodesize - 2)
- return grub_error (GRUB_ERR_BAD_FS, "HFS+ key beyond end of
node");
+ {
+ grub_free (node);
+ return grub_error (GRUB_ERR_BAD_FS, "HFS+ key beyond end of
node");
+ }
currnode = grub_be_to_cpu32 (grub_get_unaligned32 (pointer));
match = 1;
diff --git a/grub-core/fs/iso9660.c b/grub-core/fs/iso9660.c
index 91817ec1f..df9f7783b 100644
--- a/grub-core/fs/iso9660.c
+++ b/grub-core/fs/iso9660.c
@@ -279,7 +279,10 @@ grub_iso9660_susp_iterate (grub_fshelp_node_t node,
grub_off_t off,
/* Load a part of the System Usage Area. */
err = read_node (node, off, sua_size, sua);
if (err)
- return err;
+ {
+ grub_free (sua);
+ return err;
+ }
for (entry = (struct grub_iso9660_susp_entry *) sua; (char *) entry <
(char *) sua + sua_size - 1 && entry->len > 0;
entry = (struct grub_iso9660_susp_entry *)
@@ -309,7 +312,10 @@ grub_iso9660_susp_iterate (grub_fshelp_node_t node,
grub_off_t off,
err = grub_disk_read (node->data->disk, ce_block, off,
sua_size, sua);
if (err)
- return err;
+ {
+ grub_free (sua);
+ return err;
+ }
entry = (struct grub_iso9660_susp_entry *) sua;
}
diff --git a/grub-core/fs/minix.c b/grub-core/fs/minix.c
index 953df1191..5354951d1 100644
--- a/grub-core/fs/minix.c
+++ b/grub-core/fs/minix.c
@@ -374,7 +374,7 @@ grub_minix_lookup_symlink (struct grub_minix_data *data,
grub_minix_ino_t ino)
if (!symlink)
return grub_errno;
if (grub_minix_read_file (data, 0, 0, 0, sz, symlink) < 0)
- return grub_errno;
+ goto fail;
symlink[sz] = '\0';
@@ -384,10 +384,12 @@ grub_minix_lookup_symlink (struct grub_minix_data
*data, grub_minix_ino_t ino)
/* Now load in the old inode. */
if (grub_minix_read_inode (data, ino))
- return grub_errno;
+ goto fail;
grub_minix_find_file (data, symlink);
+ fail:
+ grub_free(symlink);
return grub_errno;
}
diff --git a/grub-core/fs/ntfs.c b/grub-core/fs/ntfs.c
index 3511e4e2c..bbdbe24ad 100644
--- a/grub-core/fs/ntfs.c
+++ b/grub-core/fs/ntfs.c
@@ -654,7 +654,7 @@ grub_ntfs_read_symlink (grub_fshelp_node_t node)
struct grub_ntfs_file *mft;
struct symlink_descriptor symdesc;
grub_err_t err;
- grub_uint8_t *buf16;
+ grub_uint8_t *buf16 = NULL;
char *buf, *end;
grub_size_t len;
grub_uint8_t *pa;
@@ -667,20 +667,20 @@ grub_ntfs_read_symlink (grub_fshelp_node_t node)
return NULL;
if (read_mft (mft->data, mft->buf, mft->ino))
- return NULL;
+ goto fail;
pa = locate_attr (&mft->attr, mft, GRUB_NTFS_AT_SYMLINK);
if (pa == NULL)
{
grub_error (GRUB_ERR_BAD_FS, "no $SYMLINK in MFT 0x%llx",
(unsigned long long) mft->ino);
- return NULL;
+ goto fail;
}
err = read_attr (&mft->attr, (grub_uint8_t *) &symdesc, 0,
sizeof (struct symlink_descriptor), 1, 0, 0);
if (err)
- return NULL;
+ goto fail;
switch (grub_cpu_to_le32 (symdesc.type))
{
@@ -697,23 +697,22 @@ grub_ntfs_read_symlink (grub_fshelp_node_t node)
default:
grub_error (GRUB_ERR_BAD_FS, "symlink type invalid (%x)",
grub_cpu_to_le32 (symdesc.type));
- return NULL;
+ goto fail;
}
buf16 = grub_malloc (len);
if (!buf16)
- return NULL;
+ goto fail;
err = read_attr (&mft->attr, buf16, off, len, 1, 0, 0);
if (err)
- return NULL;
+ goto fail;
buf = get_utf8 (buf16, len / 2);
if (!buf)
- {
- grub_free (buf16);
- return NULL;
- }
+ goto fail;
+
+ grub_free (mft->buf);
grub_free (buf16);
for (end = buf; *end; end++)
@@ -728,6 +727,11 @@ grub_ntfs_read_symlink (grub_fshelp_node_t node)
end -= 6;
}
return buf;
+
+ fail:
+ grub_free (mft->buf);
+ grub_free (buf16);
+ return NULL;
}
static int
diff --git a/grub-core/fs/squash4.c b/grub-core/fs/squash4.c
index 02b1f9b6d..a30e6ebe1 100644
--- a/grub-core/fs/squash4.c
+++ b/grub-core/fs/squash4.c
@@ -550,7 +550,10 @@ grub_squash_iterate_dir (grub_fshelp_node_t dir,
+ node->stack[node->stsize - 1].ino_chunk,
node->stack[node->stsize - 1].ino_offset);
if (err)
- return 0;
+ {
+ grub_free (node);
+ return 0;
+ }
if (hook ("..", GRUB_FSHELP_DIR, node, hook_data))
return 1;
@@ -600,7 +603,10 @@ grub_squash_iterate_dir (grub_fshelp_node_t dir,
grub_le_to_cpu64 (dir->data->sb.diroffset)
+ chunk, off);
if (err)
- return 0;
+ {
+ grub_free (buf);
+ return 0;
+ }
off += grub_le_to_cpu16 (di.namelen) + 1;
buf[grub_le_to_cpu16 (di.namelen) + 1] = 0;
@@ -612,11 +618,17 @@ grub_squash_iterate_dir (grub_fshelp_node_t dir,
if (grub_add (dir->stsize, 1, &sz) ||
grub_mul (sz, sizeof (dir->stack[0]), &sz) ||
grub_add (sz, sizeof (*node), &sz))
- return 0;
+ {
+ grub_free (buf);
+ return 0;
+ }
node = grub_malloc (sz);
if (! node)
- return 0;
+ {
+ grub_free (buf);
+ return 0;
+ }
grub_memcpy (node, dir, sz - sizeof(dir->stack[0]));
diff --git a/grub-core/fs/udf.c b/grub-core/fs/udf.c
index 12e88ab62..7679ea309 100644
--- a/grub-core/fs/udf.c
+++ b/grub-core/fs/udf.c
@@ -510,6 +510,20 @@ grub_udf_read_block (grub_fshelp_node_t node,
grub_disk_addr_t fileblock)
}
len = U32 (extension->ae_len);
+ /*
+ * Ensure AE length is less than block size
+ * per UDF spec v2.01 section 2.3.11.
+ *
+ * node->data->lbshift is initialized by
+ * grub_udf_mount(). lbshift has a maximum value
+ * of 3 and it does not cause an overflow here.
+ */
+ if (len < 0 || len > ((grub_ssize_t) 1 << node->data->lbshift))
+ {
+ grub_error (GRUB_ERR_BAD_FS, "invalid ae length");
+ goto fail;
+ }
+
ad = (struct grub_udf_short_ad *)
(buf + sizeof (struct grub_udf_aed));
continue;
@@ -563,6 +577,20 @@ grub_udf_read_block (grub_fshelp_node_t node,
grub_disk_addr_t fileblock)
}
len = U32 (extension->ae_len);
+ /*
+ * Ensure AE length is less than block size
+ * per UDF spec v2.01 section 2.3.11.
+ *
+ * node->data->lbshift is initialized by
+ * grub_udf_mount(). lbshift has a maximum value
+ * of 3 and it does not cause an overflow here.
+ */
+ if (len < 0 || len > ((grub_ssize_t) 1 << node->data->lbshift))
+ {
+ grub_error (GRUB_ERR_BAD_FS, "invalid ae length");
+ goto fail;
+ }
+
ad = (struct grub_udf_long_ad *)
(buf + sizeof (struct grub_udf_aed));
continue;
diff --git a/grub-core/fs/xfs.c b/grub-core/fs/xfs.c
index d6de7f1a2..b67407690 100644
--- a/grub-core/fs/xfs.c
+++ b/grub-core/fs/xfs.c
@@ -585,7 +585,10 @@ grub_xfs_read_block (grub_fshelp_node_t node,
grub_disk_addr_t fileblock)
if (grub_disk_read (node->data->disk,
GRUB_XFS_FSB_TO_BLOCK (node->data, get_fsb
(keys, i - 1 + recoffset)) << (node->data->sblock.log2_bsize -
GRUB_DISK_SECTOR_BITS),
0, node->data->bsize, leaf))
- return 0;
+ {
+ grub_free (leaf);
+ return 0;
+ }
if ((!node->data->hascrc &&
grub_strncmp ((char *) leaf->magic, "BMAP", 4)) ||
@@ -751,6 +754,7 @@ static int iterate_dir_call_hook (grub_uint64_t ino,
const char *filename,
if (err)
{
grub_print_error ();
+ grub_free (fdiro);
return 0;
}
@@ -861,7 +865,10 @@ grub_xfs_iterate_dir (grub_fshelp_node_t dir,
blk << dirblk_log2,
dirblk_size, dirblock, 0);
if (numread != dirblk_size)
- return 0;
+ {
+ grub_free (dirblock);
+ return 0;
+ }
entries = (grub_be_to_cpu32 (tail->leaf_count)
- grub_be_to_cpu32 (tail->leaf_stale));
diff --git a/grub-core/kern/file.c b/grub-core/kern/file.c
index 8d48fd50d..750177248 100644
--- a/grub-core/kern/file.c
+++ b/grub-core/kern/file.c
@@ -66,6 +66,9 @@ grub_file_open (const char *name, enum grub_file_type type)
const char *file_name;
grub_file_filter_id_t filter;
+ /* Reset grub_errno before we start. */
+ grub_errno = GRUB_ERR_NONE;
+
device_name = grub_file_get_device_name (name);
if (grub_errno)
goto fail;
diff --git a/grub-core/loader/i386/linux.c b/grub-core/loader/i386/linux.c
index edd6c2bb1..10a367629 100644
--- a/grub-core/loader/i386/linux.c
+++ b/grub-core/loader/i386/linux.c
@@ -1085,9 +1085,22 @@ grub_cmd_initrd (grub_command_t cmd __attribute__
((unused)),
addr_min = (grub_addr_t) prot_mode_target + prot_init_space;
+ /* Make sure the maximum address is able to store the initrd. */
+ if (addr_max < aligned_size)
+ {
+ grub_error (GRUB_ERR_OUT_OF_RANGE,
+ N_("the size of initrd is bigger than addr_max"));
+ goto fail;
+ }
+
/* Put the initrd as high as possible, 4KiB aligned. */
addr = (addr_max - aligned_size) & ~0xFFF;
+ grub_dprintf ("linux",
+ "Initrd at addr 0x%" PRIxGRUB_ADDR " which is expected in"
+ " ranger 0x%" PRIxGRUB_ADDR " ~ 0x%" PRIxGRUB_ADDR "\n",
+ addr, addr_min, addr_max);
+
if (addr < addr_min)
{
grub_error (GRUB_ERR_OUT_OF_RANGE, "the initrd is too big");
diff --git a/grub-core/loader/linux.c b/grub-core/loader/linux.c
index 830360172..3948302d2 100644
--- a/grub-core/loader/linux.c
+++ b/grub-core/loader/linux.c
@@ -127,12 +127,23 @@ insert_dir (const char *name, struct dir **root,
n->name = grub_strndup (cb, ce - cb);
if (ptr)
{
+ /*
+ * Create the substring with the trailing NUL byte
+ * to be included in the cpio header.
+ */
+ char *tmp_name = grub_strndup (name, ce - name);
+ if (!tmp_name) {
+ grub_free (n->name);
+ grub_free (n);
+ return grub_errno;
+ }
grub_dprintf ("linux", "Creating directory %s, %s\n", name, ce);
- ptr = make_header (ptr, name, ce - name,
+ ptr = make_header (ptr, tmp_name, ce - name + 1,
040777, 0);
+ grub_free (tmp_name);
}
if (grub_add (*size,
- ALIGN_UP ((ce - (char *) name)
+ ALIGN_UP ((ce - (char *) name + 1)
+ sizeof (struct newc_head), 4),
size))
{
@@ -191,7 +202,7 @@ grub_initrd_init (int argc, char *argv[],
grub_initrd_close (initrd_ctx);
return grub_errno;
}
- name_len = grub_strlen (initrd_ctx->components[i].newc_name);
+ name_len = grub_strlen (initrd_ctx->components[i].newc_name) + 1;
if (grub_add (initrd_ctx->size,
ALIGN_UP (sizeof (struct newc_head) + name_len, 4),
&initrd_ctx->size) ||
@@ -205,7 +216,7 @@ grub_initrd_init (int argc, char *argv[],
{
if (grub_add (initrd_ctx->size,
ALIGN_UP (sizeof (struct newc_head)
- + sizeof ("TRAILER!!!") - 1, 4),
+ + sizeof ("TRAILER!!!"), 4),
&initrd_ctx->size))
goto overflow;
free_dir (root);
@@ -233,7 +244,7 @@ grub_initrd_init (int argc, char *argv[],
initrd_ctx->size = ALIGN_UP (initrd_ctx->size, 4);
if (grub_add (initrd_ctx->size,
ALIGN_UP (sizeof (struct newc_head)
- + sizeof ("TRAILER!!!") - 1, 4),
+ + sizeof ("TRAILER!!!"), 4),
&initrd_ctx->size))
goto overflow;
free_dir (root);
@@ -297,14 +308,14 @@ grub_initrd_load (struct grub_linux_initrd_context
*initrd_ctx,
}
ptr += dir_size;
ptr = make_header (ptr, initrd_ctx->components[i].newc_name,
- grub_strlen (initrd_ctx->components[i].newc_name),
+ grub_strlen (initrd_ctx->components[i].newc_name)
+ 1,
0100777,
initrd_ctx->components[i].size);
newc = 1;
}
else if (newc)
{
- ptr = make_header (ptr, "TRAILER!!!", sizeof ("TRAILER!!!") - 1,
+ ptr = make_header (ptr, "TRAILER!!!", sizeof ("TRAILER!!!"),
0, 0);
free_dir (root);
root = 0;
@@ -327,7 +338,7 @@ grub_initrd_load (struct grub_linux_initrd_context
*initrd_ctx,
{
grub_memset (ptr, 0, ALIGN_UP_OVERHEAD (cursize, 4));
ptr += ALIGN_UP_OVERHEAD (cursize, 4);
- ptr = make_header (ptr, "TRAILER!!!", sizeof ("TRAILER!!!") - 1, 0, 0);
+ ptr = make_header (ptr, "TRAILER!!!", sizeof ("TRAILER!!!"), 0, 0);
}
free_dir (root);
root = 0;
diff --git a/grub-core/normal/cmdline.c b/grub-core/normal/cmdline.c
index 61f098244..9c6d9ade9 100644
--- a/grub-core/normal/cmdline.c
+++ b/grub-core/normal/cmdline.c
@@ -219,6 +219,8 @@ cl_set_pos (struct cmdline_term *cl_term, grub_size_t
lpos)
cl_term->pos.x = (cl_term->prompt_len + lpos) % cl_term->width;
cl_term->pos.y = cl_term->ystart
+ (cl_term->prompt_len + lpos) / cl_term->width;
+ if (cl_term->pos.y >= cl_term->height)
+ cl_term->pos.y = cl_term->height - 1;
grub_term_gotoxy (cl_term->term, cl_term->pos);
}
@@ -248,7 +250,10 @@ cl_print (struct cmdline_term *cl_term, grub_uint32_t c,
{
cl_term->pos.x = 0;
if (cl_term->pos.y >= (unsigned) (cl_term->height - 1))
- cl_term->ystart--;
+ {
+ if (cl_term->ystart > 0)
+ cl_term->ystart--;
+ }
else
cl_term->pos.y++;
grub_putcode ('\n', cl_term->term);
diff --git a/grub-core/term/i386/pc/vga_text.c
b/grub-core/term/i386/pc/vga_text.c
index 669d06fad..b88fa9d2e 100644
--- a/grub-core/term/i386/pc/vga_text.c
+++ b/grub-core/term/i386/pc/vga_text.c
@@ -63,7 +63,8 @@ static grub_uint8_t cur_color = 0x7;
static void
screen_write_char (int x, int y, short c)
{
- VGA_TEXT_SCREEN[y * COLS + x] = grub_cpu_to_le16 (c);
+ if (x < COLS && y < ROWS && x >= 0 && y >= 0)
+ VGA_TEXT_SCREEN[y * COLS + x] = grub_cpu_to_le16 (c);
}
static short
diff --git a/tests/util/grub-shell.in b/tests/util/grub-shell.in
index ce431757c..6cb72403e 100644
--- a/tests/util/grub-shell.in
+++ b/tests/util/grub-shell.in
@@ -70,6 +70,8 @@ exec_show_error () {
fi
}
+work_directory=${WORKDIR:-`mktemp -d
"${TMPDIR:-/tmp}/grub-shell.XXXXXXXXXX"`} || exit 1
+
. "${builddir}/grub-core/modinfo.sh"
qemuopts="${GRUB_QEMU_OPTS}"
serial_port=com0
@@ -79,7 +81,7 @@ pseries=n
disk="hda "
case "${grub_modinfo_target_cpu}-${grub_modinfo_platform}" in
*-emu)
- device_map=`mktemp "${TMPDIR:-/tmp}/tmp.XXXXXXXXXX"` || exit 1
+ device_map="$work_directory/device.map"
boot=emu
console=console
disk=0
@@ -313,14 +315,14 @@ for option in "$@"; do
done
if [ "x${source}" = x ] ; then
- tmpfile=`mktemp "${TMPDIR:-/tmp}/tmp.XXXXXXXXXX"` || exit 1
+ tmpfile="$work_directory/testcase.cfg"
while read REPLY; do
echo "$REPLY" >> ${tmpfile}
done
source=${tmpfile}
fi
-cfgfile=`mktemp "${TMPDIR:-/tmp}/tmp.XXXXXXXXXX"` || exit 1
+cfgfile="$work_directory/grub.cfg"
cat <<EOF >${cfgfile}
grubshell=yes
enable_progress_indicator=0
@@ -354,7 +356,8 @@ if [ $trim = 1 ]; then
echo "echo $trim_head" >>${cfgfile}
fi
-rom_directory=`mktemp -d "${TMPDIR:-/tmp}/tmp.XXXXXXXXXX"` || exit 1
+rom_directory="$work_directory/rom_directory"
+mkdir -p "$rom_directory"
for mod in ${modules}
do
@@ -375,7 +378,7 @@ test -z "$debug" || echo "GRUB script: ${cfgfile}" >&2
test -z "$debug" || echo "GRUB testcase script: ${tmpfile}" >&2
test -z "$debug" || echo "Boot device: ${boot}" >&2
-isofile=`mktemp "${TMPDIR:-/tmp}/tmp.XXXXXXXXXX"` || exit 1
+isofile="$work_directory/grub.iso"
test -z "$debug" || echo "GRUB ISO file: ${isofile}" >&2
test -z "$debug" || echo "GRUB ROM directory: ${rom_directory}" >&2
@@ -451,7 +454,7 @@ if [ x$boot = xmips_qemu ]; then
fi
if [ x$boot = xcoreboot ]; then
- imgfile=`mktemp "${TMPDIR:-/tmp}/tmp.XXXXXXXXXX"` || exit 1
+ imgfile="$work_directory/coreboot.img"
cp "${GRUB_COREBOOT_ROM}" "${imgfile}"
"${GRUB_CBFSTOOL}" "${imgfile}" add-payload -f
"${rom_directory}/coreboot.elf" -n fallback/payload
bootdev="-bios ${imgfile}"
@@ -494,14 +497,15 @@ copy_extra_files() {
}
if [ x$boot = xnet ]; then
- netdir=`mktemp -d "${TMPDIR:-/tmp}/tmp.XXXXXXXXXX"` || exit 1
+ netdir="$work_directory/netdir"
+ mkdir -p "$netdir"
pkgdatadir="${builddir}" "${builddir}/grub-mknetdir"
"--grub-mkimage=${builddir}/grub-mkimage" "--directory=${builddir}/grub-core"
"--net-directory=$netdir" ${mkrescue_args} > /dev/null
cp "${cfgfile}" "$netdir/boot/grub/grub.cfg"
cp "${source}" "$netdir/boot/grub/testcase.cfg"
[ -z "$files" ] || copy_extra_files "$netdir" $files
timeout -s KILL $timeout "${qemu}" ${qemuopts} ${serial_null} -serial
file:/dev/stdout -boot n -net
"user,tftp=$netdir,bootfile=/boot/grub/${grub_modinfo_target_cpu}-${grub_modinfo_platform}/core.$netbootext"
-net nic | cat | tr -d "\r" | do_trim
elif [ x$boot = xemu ]; then
- rootdir="$(mktemp -d "${TMPDIR:-/tmp}/tmp.XXXXXXXXXX")"
+ rootdir="$work_directory/rootdir"
grubdir="$rootdir/boot/grub"
mkdir -p "$grubdir/fonts"
mkdir -p "$grubdir/themes"
@@ -516,7 +520,7 @@ elif [ x$boot = xemu ]; then
cp "${cfgfile}" "$grubdir/grub.cfg"
cp "${source}" "$grubdir/testcase.cfg"
[ -z "$files" ] || copy_extra_files "$rootdir" $files
- roottar="$(mktemp "${TMPDIR:-/tmp}/tmp.XXXXXXXXXX")"
+ roottar="$work_directory/root.tar"
(cd "$rootdir"; tar cf "$roottar" .)
"${builddir}/grub-core/grub-emu" -m "$device_map" --memdisk "$roottar"
-r memdisk -d "/boot/grub" | tr -d "\r" | do_trim
test -n "$debug" || rm -rf "$rootdir"
diff --git a/util/bash-completion.d/grub-completion.bash.in
b/util/bash-completion.d/grub-completion.bash.in
index 44bf135b9..213ce1e57 100644
--- a/util/bash-completion.d/grub-completion.bash.in
+++ b/util/bash-completion.d/grub-completion.bash.in
@@ -52,14 +52,18 @@ __grubcomp () {
COMPREPLY=()
;;
*)
- local IFS=' '$'\t'$'\n'
- COMPREPLY=($(compgen -P "${2-}" -W "${1-}" -S "${4-}" -- "$cur"))
+ local line IFS=' '$'\t'$'\n'
+ COMPREPLY=()
+ while read -r line; do
+ COMPREPLY+=("${line}")
+ done < <(compgen -P "${2-}" -W "${1-}" -S "${4-}" -- "$cur")
;;
esac
}
# Function that return long options from the help of the command
# - arg: $1 (optional) command to get the long options from
+# shellcheck disable=SC2120
__grub_get_options_from_help () {
local prog
@@ -112,28 +116,35 @@ __grub_get_last_option () {
__grub_list_menuentries () {
local cur="${COMP_WORDS[COMP_CWORD]}"
- local config_file=$(__grub_dir)/grub.cfg
+ local config_file
+ config_file=$(__grub_dir)/grub.cfg
if [ -f "$config_file" ];then
- local IFS=$'\n'
- COMPREPLY=( $(compgen \
- -W "$( awk -F "[\"']" '/menuentry/ { print $2 }' $config_file )"
\
- -- "$cur" )) #'# Help emacs syntax highlighting
+ local line IFS=$'\n'
+ COMPREPLY=()
+ while read -r line; do
+ COMPREPLY+=("${line}")
+ done < <(compgen \
+ -W "$( awk -F "[\"']" '/menuentry/ { print $2 }'
$config_file )" \
+ -- "$cur" ) #'# Help emacs syntax highlighting
fi
}
__grub_list_modules () {
- local grub_dir=$(__grub_dir)
- local IFS=$'\n'
- COMPREPLY=( $( compgen -f -X '!*/*.mod' -- "${grub_dir}/$cur" | {
- while read -r tmp; do
- [ -n $tmp ] && {
- tmp=${tmp##*/}
- printf '%s\n' ${tmp%.mod}
- }
- done
- }
- ))
+ local grub_dir
+ grub_dir=$(__grub_dir)
+ local line tmp IFS=$'\n'
+ COMPREPLY=()
+ while read -r line; do
+ COMPREPLY+=("${line}")
+ done < <(compgen -f -X '!*/*.mod' -- "${grub_dir}/$cur" | {
+ while read -r tmp; do
+ [ -n "$tmp" ] && {
+ tmp=${tmp##*/}
+ printf '%s\n' ${tmp%.mod}
+ }
+ done
+ })
}
#
diff --git a/util/grub-install.c b/util/grub-install.c
index 1c0ece7f1..53b464804 100644
--- a/util/grub-install.c
+++ b/util/grub-install.c
@@ -827,6 +827,19 @@ fill_core_services (const char *core_services)
free (sysv_plist);
}
+#ifdef __linux__
+static void
+try_open (const char *path)
+{
+ FILE *f;
+
+ f = grub_util_fopen (path, "r+");
+ if (f == NULL)
+ grub_util_error (_("Unable to open %s: %s"), path, strerror (errno));
+ fclose (f);
+}
+#endif
+
int
main (int argc, char *argv[])
{
@@ -1026,6 +1039,20 @@ main (int argc, char *argv[])
break;
}
+ switch (platform)
+ {
+ case GRUB_INSTALL_PLATFORM_I386_IEEE1275:
+ case GRUB_INSTALL_PLATFORM_POWERPC_IEEE1275:
+#ifdef __linux__
+ /* On Linux, ensure /dev/nvram is _functional_. */
+ if (update_nvram)
+ try_open ("/dev/nvram");
+#endif
+ break;
+ default:
+ break;
+ }
+
/* Find the EFI System Partition. */
if (is_efi)
diff --git a/util/grub.d/10_linux.in b/util/grub.d/10_linux.in
index 7263f2983..cc393be7e 100644
--- a/util/grub.d/10_linux.in
+++ b/util/grub.d/10_linux.in
@@ -43,13 +43,11 @@ case ${GRUB_DEVICE} in
;;
esac
-if [ "x${GRUB_CMDLINE_LINUX_RECOVERY}" = "x" ] ; then
- GRUB_CMDLINE_LINUX_RECOVERY=single
-fi
+: ${GRUB_CMDLINE_LINUX_RECOVERY:=single}
# Default to disabling partition uuid support to maintian compatibility with
# older kernels.
-GRUB_DISABLE_LINUX_PARTUUID=${GRUB_DISABLE_LINUX_PARTUUID-true}
+: ${GRUB_DISABLE_LINUX_PARTUUID=true}
# btrfs may reside on multiple devices. We cannot pass them as value of
root= parameter
# and mounting btrfs requires user space scanning, so force UUID in this
case.
diff --git a/util/grub.d/20_linux_xen.in b/util/grub.d/20_linux_xen.in
index 386bfb9be..c1ebd0953 100644
--- a/util/grub.d/20_linux_xen.in
+++ b/util/grub.d/20_linux_xen.in
@@ -43,13 +43,11 @@ case ${GRUB_DEVICE} in
;;
esac
-if [ "x${GRUB_CMDLINE_LINUX_RECOVERY}" = "x" ] ; then
- GRUB_CMDLINE_LINUX_RECOVERY=single
-fi
+: ${GRUB_CMDLINE_LINUX_RECOVERY:=single}
# Default to disabling partition uuid support to maintian compatibility with
# older kernels.
-GRUB_DISABLE_LINUX_PARTUUID=${GRUB_DISABLE_LINUX_PARTUUID-true}
+: ${GRUB_DISABLE_LINUX_PARTUUID=true}
# btrfs may reside on multiple devices. We cannot pass them as value of
root= parameter
# and mounting btrfs requires user space scanning, so force UUID in this
case.
diff --git a/util/grub.d/30_uefi-firmware.in b/util/grub.d/30_uefi-firmware.in
index c1731e5bb..1c2365ddb 100644
--- a/util/grub.d/30_uefi-firmware.in
+++ b/util/grub.d/30_uefi-firmware.in
@@ -31,10 +31,12 @@ LABEL="UEFI Firmware Settings"
gettext_printf "Adding boot menu entry for UEFI Firmware Settings ...\n" >&2
cat << EOF
-fwsetup --is-supported
-if [ "\$grub_platform" = "efi" -a "\$?" = 0 ]; then
- menuentry '$LABEL' \$menuentry_id_option 'uefi-firmware' {
- fwsetup
- }
+if [ "\$grub_platform" = "efi" ]; then
+ fwsetup --is-supported
+ if [ "\$?" = 0 ]; then
+ menuentry '$LABEL' \$menuentry_id_option 'uefi-firmware' {
+ fwsetup
+ }
+ fi
fi
EOF
docs/grub.texi | 80 +++++++
grub-core/Makefile.core.def | 5 +
grub-core/disk/plainmount.c | 458 ++++++++++++++++++++++++++++++++++++
3 files changed, 543 insertions(+)
create mode 100644 grub-core/disk/plainmount.c
diff --git a/docs/grub.texi b/docs/grub.texi
index 50c811a88..8b1a21166 100644
--- a/docs/grub.texi
+++ b/docs/grub.texi
@@ -4306,6 +4306,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
@@ -4593,6 +4594,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
@node cutmem
@@ -5155,6 +5164,77 @@ to generate password hashes. @xref{Security}.
@end deffn
+@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.
+@end deffn
+
+
@node play
@subsection play
diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def
index 95942fc8c..ba967aac8 100644
--- a/grub-core/Makefile.core.def
+++ b/grub-core/Makefile.core.def
@@ -1184,6 +1184,11 @@ module = {
common = disk/cryptodisk.c;
};
+module = {
+ name = plainmount;
+ common = disk/plainmount.c;
+};
+
module = {
name = json;
common = lib/json/json.c;
diff --git a/grub-core/disk/plainmount.c b/grub-core/disk/plainmount.c
new file mode 100644
index 000000000..47e64805f
--- /dev/null
+++ b/grub-core/disk/plainmount.c
@@ -0,0 +1,458 @@
+/*
+ * 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 <grub/cryptodisk.h>
+#include <grub/dl.h>
+#include <grub/err.h>
+#include <grub/extcmd.h>
+#include <grub/partition.h>
+#include <grub/file.h>
+
+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[] =
+ {
+ /* 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 = grub_cryptodisk_setkey (dev, key, size);
+ if (code != 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 = 0;
+
+ /* Size of user_uuid is checked in main func */
+ if (user_uuid != NULL)
+ grub_strcpy (dev->uuid, 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] == ' ');
+ grub_memcpy (dev->uuid, PLAINMOUNT_DEFAULT_UUID, pos);
+ }
+ COMPILE_TIME_ASSERT (sizeof (dev->uuid) >= 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 = grub_disk_native_sectors (disk);
+ if (dev->total_sectors == 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 = grub_log2ull (sector_size);
+ dev->total_sectors = grub_convert_sector (dev->total_sectors,
+ GRUB_DISK_SECTOR_BITS,
+ dev->log_sector_size);
+ if (dev->total_sectors == 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=%d, total_sectors=%"
+ PRIuGRUB_UINT64_T"\n", dev->log_sector_size,
dev->total_sectors);
+ 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 = GRUB_ERR_NONE;
+
+ /* Support none (plain) hash */
+ if (grub_strcmp (hash, "plain") == 0)
+ {
+ dev->hash = NULL;
+ return err;
+ }
+
+ /* Hash argument was checked at main func */
+ dev->hash = grub_crypto_lookup_md_by_name (hash);
+ len = dev->hash->mdlen;
+
+ alloc_size = 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 = grub_zalloc (alloc_size + (alloc_size / len) + 1);
+ derived_hash = grub_zalloc (GRUB_CRYPTODISK_MAX_KEYLEN * 2);
+ if (p == NULL || derived_hash == NULL)
+ {
+ err = grub_error (GRUB_ERR_OUT_OF_MEMORY, "out of memory");
+ goto fail;
+ }
+ dh = derived_hash;
+
+ /*
+ * Hash password. Adapted from cryptsetup.
+ * https://gitlab.com/cryptsetup/cryptsetup/-/blob/main/lib/crypt_plain.c
+ */
+ for (round = 0, size = alloc_size; size; round++, dh += len, size -= len)
+ {
+ for (i = 0; i < round; i++)
+ p[i] = 'A';
+
+ grub_memcpy (p + i, (char*) key_data, password_size);
+
+ if (len > size)
+ len = size;
+
+ grub_crypto_hash (dev->hash, dh, p, password_size + round);
+ }
+ grub_memcpy (key_data, derived_hash, key_size);
+
+ fail:
+ 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 = grub_file_open (keyfile, GRUB_FILE_TYPE_NONE);
+ if (g_keyfile == NULL)
+ return grub_error (GRUB_ERR_FILE_NOT_FOUND, N_("cannot open keyfile %s"),
+ keyfile);
+
+ if (grub_file_seek (g_keyfile, keyfile_offset) == (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_UINT64_T") and offset (%"PRIuGRUB_SIZE")"),
+ key_size, g_keyfile->size, keyfile_offset);
+
+ if (grub_file_read (g_keyfile, key_data, key_size) != (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 = ctxt->state;
+ grub_cryptodisk_t dev = NULL;
+ grub_disk_t disk = NULL;
+ const gcry_md_spec_t *gcry_hash;
+ char *diskname, *disklast = NULL, *cipher, *mode, *hash, *keyfile, *uuid;
+ grub_size_t len, key_size, sector_size, keyfile_offset = 0, password_size =
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 = 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) >
+ GRUB_CRYPTODISK_MAX_UUID_LENGTH - 1)
+ return grub_error (GRUB_ERR_BAD_ARGUMENT,
+ N_("specified UUID exceeds maximum size"));
+ if (state[OPTION_UUID].set && grub_strlen (state[OPTION_UUID].arg) == 1)
+ return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("specified UUID too short"));
+
+ /* Parse plainmount arguments */
+ grub_errno = GRUB_ERR_NONE;
+ keyfile_offset = 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] == '\0' || *p != '\0' ||
+ grub_errno != GRUB_ERR_NONE))
+ return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("unrecognized keyfile
offset"));
+
+ sector_size = 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] ==
'\0' ||
+ *p != '\0' || grub_errno !=
GRUB_ERR_NONE))
+ return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("unrecognized sector size"));
+
+ /* Check key size */
+ key_size = grub_strtoull (state[OPTION_KEY_SIZE].arg, &p, 0);
+ if (state[OPTION_KEY_SIZE].arg[0] == '\0' || *p != '\0' ||
+ grub_errno != GRUB_ERR_NONE)
+ return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("unrecognized key size"));
+ if ((key_size % GRUB_CHAR_BIT) != 0)
+ return grub_error (GRUB_ERR_BAD_ARGUMENT,
+ N_("key size is not multiple of %d bits"),
GRUB_CHAR_BIT);
+ key_size = 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)) != 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 = state[OPTION_HASH].set ? grub_strdup (state[OPTION_HASH].arg) : NULL;
+ cipher = grub_strdup (state[OPTION_CIPHER].arg);
+ keyfile = state[OPTION_KEYFILE].set ?
+ grub_strdup (state[OPTION_KEYFILE].arg) : NULL;
+ dev = grub_zalloc (sizeof *dev);
+ key_data = grub_zalloc (GRUB_CRYPTODISK_MAX_PASSPHRASE);
+ uuid = state[OPTION_UUID].set ? grub_strdup (state[OPTION_UUID].arg) : NULL;
+ if ((state[OPTION_HASH].set && hash == NULL) || cipher == NULL || dev ==
NULL ||
+ (state[OPTION_KEYFILE].set && keyfile == NULL) || key_data == NULL ||
+ (state[OPTION_UUID].set && uuid == NULL))
+ {
+ err = grub_error (GRUB_ERR_OUT_OF_MEMORY, "out of memory");
+ goto fail;
+ }
+
+ /* 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 = grub_strlen (state[OPTION_PASSWORD].arg);
+ grub_strcpy ((char*) key_data, state[OPTION_PASSWORD].arg);
+ }
+
+ /* Set cipher mode (tested above) */
+ mode = grub_strchr (cipher,'-');
+ *mode++ = '\0';
+
+ /* Check cipher */
+ err = grub_cryptodisk_setcipher (dev, cipher, mode);
+ if (err != GRUB_ERR_NONE)
+ {
+ if (err == GRUB_ERR_FILE_NOT_FOUND)
+ err = grub_error (GRUB_ERR_BAD_ARGUMENT, N_("invalid cipher %s"),
cipher);
+ else if (err == GRUB_ERR_BAD_ARGUMENT)
+ err = grub_error (GRUB_ERR_BAD_ARGUMENT, N_("invalid mode %s"), mode);
+ else
+ err = grub_error (GRUB_ERR_BAD_ARGUMENT, N_("invalid cipher %s or mode
%s"),
+ cipher, mode);
+ goto fail;
+ }
+
+ /* Open SOURCE disk */
+ diskname = args[0];
+ len = grub_strlen (diskname);
+ if (len && diskname[0] == '(' && diskname[len - 1] == ')')
+ {
+ disklast = &diskname[len - 1];
+ *disklast = '\0';
+ diskname++;
+ }
+ disk = grub_disk_open (diskname);
+ if (disk == NULL)
+ {
+ if (disklast)
+ *disklast = ')';
+ err = grub_error (GRUB_ERR_BAD_ARGUMENT, N_("cannot open disk %s"),
diskname);
+ goto fail;
+ }
+
+ /* Get password from console */
+ if (!state[OPTION_KEYFILE].set && key_data[0] == '\0')
+ {
+ char *part = grub_partition_get_name (disk->partition);
+ grub_printf_ (N_("Enter passphrase for %s%s%s: "), disk->name,
+ disk->partition != NULL ? "," : "",
+ part != NULL ? part : N_("UNKNOWN"));
+ grub_free (part);
+
+ if (!grub_password_get ((char*) key_data, GRUB_CRYPTODISK_MAX_PASSPHRASE -
1))
+ {
+ err = grub_error (GRUB_ERR_BAD_ARGUMENT, N_("error reading password"));
+ goto fail;
+ }
+ /*
+ * Password from interactive console is limited to C-string.
+ * Arbitrary data keys are supported via keyfiles.
+ */
+ password_size = grub_strlen ((char*) key_data);
+ }
+
+ /* 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=%s, hash=%s, key_size=%"
+ PRIuGRUB_SIZE ", keyfile=%s, keyfile offset=%" PRIuGRUB_SIZE
"\n",
+ cipher, hash, key_size, keyfile, keyfile_offset);
+
+ err = plainmount_configure_sectors (dev, disk, sector_size);
+ if (err != GRUB_ERR_NONE)
+ goto fail;
+
+ /* Configure keyfile or password */
+ if (state[OPTION_KEYFILE].set)
+ err = plainmount_configure_keyfile (keyfile, key_data, key_size,
keyfile_offset);
+ else
+ err = plainmount_configure_password (dev, hash, key_data, key_size,
password_size);
+ if (err != GRUB_ERR_NONE)
+ goto fail;
+
+ err = plainmount_setkey (dev, key_data, key_size);
+ if (err != GRUB_ERR_NONE)
+ goto fail;
+
+ err = grub_cryptodisk_insert (dev, diskname, disk);
+ if (err != GRUB_ERR_NONE)
+ goto fail;
+
+ dev->modname = "plainmount";
+ dev->source_disk = disk;
+ plainmount_set_uuid (dev, uuid);
+
+ fail:
+ grub_free (hash);
+ grub_free (cipher);
+ grub_free (keyfile);
+ grub_free (key_data);
+ grub_free (uuid);
+ if (err != GRUB_ERR_NONE && disk != NULL)
+ grub_disk_close (disk);
+ if (err != GRUB_ERR_NONE)
+ grub_free (dev);
+ return err;
+}
+
+static grub_extcmd_t cmd;
+GRUB_MOD_INIT (plainmount)
+{
+ cmd = 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]] <SOURCE>"),
+ N_("Open partition encrypted in plain mode."),
+ options);
+}
+
+GRUB_MOD_FINI (plainmount)
+{
+ grub_unregister_extcmd (cmd);
+}
--
2.39.0
- [PATCH v10] plainmount: Support plain encryption mode,
Maxim Fomin <=