This patch prepares for using an environment block stored in a reserved area of the filesystem. It uses constant GRUB_ENV_BTRFS_OFFSET at 256 KiB in the Btrfs header. It also introduces the fs_envblk_spec and fs_envblk structures together with the probe_fs_envblk function to identify the root filesystem and to avoid configurations that involve diskfilter or cryptodisk.
The probe is only invoked when grub-editenv is working on the default environment file path. This restriction ensures that probing and possible raw device access are not triggered for arbitrary user supplied paths, but only for the standard grubenv file. In that case the code checks if the filename equals DEFAULT_ENVBLK_PATH and then calls probe_fs_envblk with fs_envblk_spec. The result is stored in the global fs_envblk handle. At this stage the external environment block is only detected and recorded, and the behavior of grub-editenv is unchanged. Signed-off-by: Michael Chang <[email protected]> Reviewed-by: Neal Gompa <[email protected]> Reviewed-by: Avnish Chouhan <[email protected]> --- util/grub-editenv.c | 164 +++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 163 insertions(+), 1 deletion(-) diff --git a/util/grub-editenv.c b/util/grub-editenv.c index db6f187cc..e650cbcd0 100644 --- a/util/grub-editenv.c +++ b/util/grub-editenv.c @@ -23,8 +23,11 @@ #include <grub/util/misc.h> #include <grub/lib/envblk.h> #include <grub/i18n.h> -#include <grub/emu/hostfile.h> +#include <grub/emu/hostdisk.h> #include <grub/util/install.h> +#include <grub/emu/getroot.h> +#include <grub/fs.h> +#include <grub/crypto.h> #include <stdio.h> #include <unistd.h> @@ -120,6 +123,36 @@ block, use `rm %s'."), NULL, help_filter, NULL }; +struct fs_envblk_spec { + const char *fs_name; + off_t offset; + size_t size; +}; +typedef struct fs_envblk_spec fs_envblk_spec_t; + +struct fs_envblk { + fs_envblk_spec_t *spec; + const char *dev; +}; +typedef struct fs_envblk *fs_envblk_t; + +/* + * fs_envblk_spec describes the file-system specific layout of reserved raw + * blocks used as environment blocks. At present only Btrfs is supported. Other + * file-systems may be added if they provide a similar facility and avoid the + * limitation of writing to COW. + * + * Note: If this table is modified, also update + * grub-core/fs/btrfs.c::btrfs_head, which defines the layout in the Btrfs + * header and exports GRUB_ENV_BTRFS_OFFSET, so that both stay consistent. + */ +static fs_envblk_spec_t fs_envblk_spec[] = { + { "btrfs", GRUB_ENV_BTRFS_OFFSET, GRUB_DISK_SECTOR_SIZE }, + { NULL, 0, 0 } +}; + +static fs_envblk_t fs_envblk = NULL; + static grub_envblk_t open_envblk_file (const char *name) { @@ -253,6 +286,132 @@ unset_variables (const char *name, int argc, char *argv[]) grub_envblk_close (envblk); } +static bool +is_abstraction (grub_device_t dev) +{ + if (dev == NULL || dev->disk == NULL) + return false; + + if (dev->disk->dev->id == GRUB_DISK_DEVICE_DISKFILTER_ID || + dev->disk->dev->id == GRUB_DISK_DEVICE_CRYPTODISK_ID) + return true; + + return false; +} + +static fs_envblk_t +probe_fs_envblk (fs_envblk_spec_t *spec) +{ + char **grub_devices = NULL; + char **curdev, **curdrive; + size_t ndev = 0; + char **grub_drives = NULL; + grub_device_t grub_dev = NULL; + grub_fs_t grub_fs = NULL; + char *devname = NULL; + fs_envblk_spec_t *p; + bool have_abstraction = false; + + grub_util_biosdisk_init (DEFAULT_DEVICE_MAP); + grub_init_all (); + grub_gcry_init_all (); + + grub_lvm_fini (); + grub_mdraid09_fini (); + grub_mdraid1x_fini (); + grub_diskfilter_fini (); + grub_diskfilter_init (); + grub_mdraid09_init (); + grub_mdraid1x_init (); + grub_lvm_init (); + + grub_devices = grub_guess_root_devices (DEFAULT_DIRECTORY); + + if (grub_devices == NULL || grub_devices[0] == NULL) + { + grub_util_warn (_("cannot find a device for %s (is /dev mounted?)"), DEFAULT_DIRECTORY); + goto cleanup_0; + } + + devname = xstrdup (grub_devices[0]); + + for (curdev = grub_devices; *curdev != NULL; curdev++, ndev++) + grub_util_pull_device (*curdev); + + grub_drives = xcalloc ((ndev + 1), sizeof (grub_drives[0])); + + for (curdev = grub_devices, curdrive = grub_drives; *curdev != NULL; curdev++, + curdrive++) + { + *curdrive = grub_util_get_grub_dev (*curdev); + if (*curdrive == NULL) + { + grub_util_warn (_("cannot find a GRUB drive for %s. Check your device.map"), + *curdev); + goto cleanup_0; + } + } + *curdrive = NULL; + + grub_dev = grub_device_open (grub_drives[0]); + if (grub_dev == NULL) + { + grub_util_warn (_("cannot open device %s: %s"), grub_drives[0], grub_errmsg); + grub_errno = GRUB_ERR_NONE; + goto cleanup_0; + } + + grub_fs = grub_fs_probe (grub_dev); + if (grub_fs == NULL) + { + grub_util_warn (_("cannot probe fs for %s: %s"), grub_drives[0], grub_errmsg); + grub_errno = GRUB_ERR_NONE; + goto cleanup_0; + } + + have_abstraction = is_abstraction (grub_dev); + for (curdrive = grub_drives + 1; *curdrive != NULL && have_abstraction == false; curdrive++) + { + grub_device_t dev = grub_device_open (*curdrive); + + if (dev == NULL) + continue; + have_abstraction = is_abstraction (dev); + grub_device_close (dev); + } + + cleanup_0: + if (grub_devices != NULL) + for (curdev = grub_devices; *curdev != NULL; curdev++) + free (*curdev); + free (grub_devices); + free (grub_drives); + grub_device_close (grub_dev); + grub_gcry_fini_all (); + grub_fini_all (); + grub_util_biosdisk_fini (); + + if (grub_fs == NULL) + goto cleanup_1; + + for (p = spec; p->fs_name != NULL; p++) + { + if (strcmp (grub_fs->name, p->fs_name) == 0 && have_abstraction == false) + { + fs_envblk = xmalloc (sizeof (fs_envblk_t)); + fs_envblk->spec = p; + fs_envblk->dev = devname; + return fs_envblk; + } + } + + cleanup_1: + free (devname); + + return NULL; +} + + int main (int argc, char *argv[]) { @@ -284,6 +443,9 @@ main (int argc, char *argv[]) command = argv[curindex++]; } + if (strcmp (filename, DEFAULT_ENVBLK_PATH) == 0) + fs_envblk = probe_fs_envblk (fs_envblk_spec); + if (strcmp (command, "create") == 0) grub_util_create_envblk_file (filename); else if (strcmp (command, "list") == 0) -- 2.51.0 _______________________________________________ Grub-devel mailing list [email protected] https://lists.gnu.org/mailman/listinfo/grub-devel
