On Mon, Oct 07, 2024 at 09:40:40PM GMT, Vladimir 'phcoder' Serbinenko wrote:
> What do you try to achieve with this that can't be achieved with using full
> path? We should avoid using hidden state for directory parsing. Solaris
> GRUB legacy used it for ZFS and it was a mess.

If a path is relative to the default subvolume, it cannot access files
outside of the default subvolume tree. This patch enables access to
files in other subvolumes by mounting them to a specific directory

Thanks,
Michael

> 
> Le lun. 7 oct. 2024, 21:22, Leo Sandoval <lsand...@redhat.com> a écrit :
> 
> > From: Michael Chang <mch...@suse.com>
> >
> > Signed-off-by: Michael Chang <mch...@suse.com>
> > Signed-off-by: Robbie Harwood <rharw...@redhat.com>
> > ---
> >  grub-core/fs/btrfs.c            | 195 +++++++++++++++++++++++++++++++-
> >  grub-core/osdep/linux/getroot.c | 148 +++++++++++++++++++++++-
> >  include/grub/emu/getroot.h      |   5 +
> >  util/grub-install.c             |  49 ++++++++
> >  4 files changed, 392 insertions(+), 5 deletions(-)
> >
> > diff --git a/grub-core/fs/btrfs.c b/grub-core/fs/btrfs.c
> > index d47f9ab03..d44a1c73b 100644
> > --- a/grub-core/fs/btrfs.c
> > +++ b/grub-core/fs/btrfs.c
> > @@ -41,6 +41,7 @@
> >  #include <grub/command.h>
> >  #include <grub/env.h>
> >  #include <grub/extcmd.h>
> > +#include <grub/list.h>
> >  #include <grub/crypto.h>
> >  #include <grub/diskfilter.h>
> >  #include <grub/safemath.h>
> > @@ -266,6 +267,12 @@ static grub_err_t
> >  grub_btrfs_read_logical (struct grub_btrfs_data *data,
> >                          grub_disk_addr_t addr, void *buf, grub_size_t
> > size,
> >                          int recursion_depth);
> > +static grub_err_t
> > +get_root (struct grub_btrfs_data *data, struct grub_btrfs_key *key,
> > +         grub_uint64_t *tree, grub_uint8_t *type);
> > +
> > +grub_uint64_t
> > +find_mtab_subvol_tree (const char *path, char **path_in_subvol);
> >
> >  static grub_err_t
> >  read_sblock (grub_disk_t disk, struct grub_btrfs_superblock *sb)
> > @@ -1302,9 +1309,26 @@ lookup_root_by_name(struct grub_btrfs_data *data,
> > const char *path)
> >    grub_err_t err;
> >    grub_uint64_t tree = 0;
> >    grub_uint8_t type;
> > +  grub_uint64_t saved_tree;
> >    struct grub_btrfs_key key;
> >
> > +  if (path[0] == '\0')
> > +    {
> > +      data->fs_tree = 0;
> > +      return GRUB_ERR_NONE;
> > +    }
> > +
> > +  err = get_root (data, &key, &tree, &type);
> > +  if (err)
> > +    return err;
> > +
> > +  saved_tree = data->fs_tree;
> > +  data->fs_tree = tree;
> > +
> >    err = find_path (data, path, &key, &tree, &type);
> > +
> > +  data->fs_tree = saved_tree;
> > +
> >    if (err)
> >        return grub_error(GRUB_ERR_FILE_NOT_FOUND, "couldn't locate %s\n",
> > path);
> >
> > @@ -2316,11 +2340,20 @@ grub_btrfs_dir (grub_device_t device, const char
> > *path,
> >    grub_uint64_t tree;
> >    grub_uint8_t type;
> >    grub_size_t est_size = 0;
> > +  char *new_path = NULL;
> >
> >    if (!data)
> >      return grub_errno;
> >
> > -  err = find_path (data, path, &key_in, &tree, &type);
> > +  tree = find_mtab_subvol_tree (path, &new_path);
> > +
> > +  if (tree)
> > +    data->fs_tree = tree;
> > +
> > +  err = find_path (data, new_path ? new_path : path, &key_in, &tree,
> > &type);
> > +  if (new_path)
> > +    grub_free (new_path);
> > +
> >    if (err)
> >      {
> >        grub_btrfs_unmount (data);
> > @@ -2447,11 +2480,21 @@ grub_btrfs_open (struct grub_file *file, const
> > char *name)
> >    struct grub_btrfs_inode inode;
> >    grub_uint8_t type;
> >    struct grub_btrfs_key key_in;
> > +  grub_uint64_t tree;
> > +  char *new_path = NULL;
> >
> >    if (!data)
> >      return grub_errno;
> >
> > -  err = find_path (data, name, &key_in, &data->tree, &type);
> > +  tree = find_mtab_subvol_tree (name, &new_path);
> > +
> > +  if (tree)
> > +    data->fs_tree = tree;
> > +
> > +  err = find_path (data, new_path ? new_path : name, &key_in,
> > &data->tree, &type);
> > +  if (new_path)
> > +    grub_free (new_path);
> > +
> >    if (err)
> >      {
> >        grub_btrfs_unmount (data);
> > @@ -2686,6 +2729,150 @@ grub_cmd_btrfs_info (grub_command_t cmd
> > __attribute__ ((unused)), int argc,
> >    return 0;
> >  }
> >
> > +struct grub_btrfs_mtab
> > +{
> > +  struct grub_btrfs_mtab *next;
> > +  struct grub_btrfs_mtab **prev;
> > +  char *path;
> > +  char *subvol;
> > +  grub_uint64_t tree;
> > +};
> > +
> > +typedef struct grub_btrfs_mtab* grub_btrfs_mtab_t;
> > +
> > +static struct grub_btrfs_mtab *btrfs_mtab;
> > +
> > +#define FOR_GRUB_MTAB(var) FOR_LIST_ELEMENTS (var, btrfs_mtab)
> > +#define FOR_GRUB_MTAB_SAFE(var, next) FOR_LIST_ELEMENTS_SAFE((var),
> > (next), btrfs_mtab)
> > +
> > +static void
> > +add_mountpoint (const char *path, const char *subvol, grub_uint64_t tree)
> > +{
> > +  grub_btrfs_mtab_t m = grub_malloc (sizeof (*m));
> > +
> > +  m->path = grub_strdup (path);
> > +  m->subvol = grub_strdup (subvol);
> > +  m->tree = tree;
> > +  grub_list_push (GRUB_AS_LIST_P (&btrfs_mtab), GRUB_AS_LIST (m));
> > +}
> > +
> > +static grub_err_t
> > +grub_cmd_btrfs_mount_subvol (grub_command_t cmd __attribute__ ((unused)),
> > int argc,
> > +                    char **argv)
> > +{
> > +  char *devname, *dirname, *subvol;
> > +  struct grub_btrfs_key key_in;
> > +  grub_uint8_t type;
> > +  grub_uint64_t tree;
> > +  grub_uint64_t saved_tree;
> > +  grub_err_t err;
> > +  struct grub_btrfs_data *data = NULL;
> > +  grub_device_t dev = NULL;
> > +
> > +  if (argc < 3)
> > +    return grub_error (GRUB_ERR_BAD_ARGUMENT, "required <dev> <dir> and
> > <subvol>");
> > +
> > +  devname = grub_file_get_device_name(argv[0]);
> > +  dev = grub_device_open (devname);
> > +  grub_free (devname);
> > +
> > +  if (!dev)
> > +    {
> > +      err = grub_errno;
> > +      goto err_out;
> > +    }
> > +
> > +  dirname = argv[1];
> > +  subvol = argv[2];
> > +
> > +  data = grub_btrfs_mount (dev);
> > +  if (!data)
> > +    {
> > +      err = grub_errno;
> > +      goto err_out;
> > +    }
> > +
> > +  err = find_path (data, dirname, &key_in, &tree, &type);
> > +  if (err)
> > +    goto err_out;
> > +
> > +  if (type !=  GRUB_BTRFS_DIR_ITEM_TYPE_DIRECTORY)
> > +    {
> > +      err = grub_error (GRUB_ERR_BAD_FILE_TYPE, N_("not a directory"));
> > +      goto err_out;
> > +    }
> > +
> > +  err = get_root (data, &key_in, &tree, &type);
> > +
> > +  if (err)
> > +    goto err_out;
> > +
> > +  saved_tree = data->fs_tree;
> > +  data->fs_tree = tree;
> > +  err = find_path (data, subvol, &key_in, &tree, &type);
> > +  data->fs_tree = saved_tree;
> > +
> > +  if (err)
> > +    goto err_out;
> > +
> > +  if (key_in.object_id != grub_cpu_to_le64_compile_time
> > (GRUB_BTRFS_OBJECT_ID_CHUNK) || tree == 0)
> > +    {
> > +      err = grub_error (GRUB_ERR_BAD_FILE_TYPE, "%s: not a subvolume\n",
> > subvol);
> > +      goto err_out;
> > +    }
> > +
> > +  grub_btrfs_unmount (data);
> > +  grub_device_close (dev);
> > +  add_mountpoint (dirname, subvol, tree);
> > +
> > +  return GRUB_ERR_NONE;
> > +
> > +err_out:
> > +
> > +  if (data)
> > +    grub_btrfs_unmount (data);
> > +
> > +  if (dev)
> > +    grub_device_close (dev);
> > +
> > +  return err;
> > +}
> > +
> > +grub_uint64_t
> > +find_mtab_subvol_tree (const char *path, char **path_in_subvol)
> > +{
> > +  grub_btrfs_mtab_t m, cm;
> > +  grub_uint64_t tree;
> > +
> > +  if (!path || !path_in_subvol)
> > +    return 0;
> > +
> > +  *path_in_subvol = NULL;
> > +  tree = 0;
> > +  cm = NULL;
> > +
> > +  FOR_GRUB_MTAB (m)
> > +    {
> > +      if (grub_strncmp (path, m->path, grub_strlen (m->path)) == 0)
> > +       {
> > +         if (!cm)
> > +           cm = m;
> > +         else
> > +           if (grub_strcmp (m->path, cm->path) > 0)
> > +             cm = m;
> > +       }
> > +    }
> > +
> > +  if (cm)
> > +    {
> > +      const char *s = path + grub_strlen (cm->path);
> > +      *path_in_subvol = (s[0] == '\0') ? grub_strdup ("/") : grub_strdup
> > (s);
> > +      tree = cm->tree;
> > +    }
> > +
> > +  return tree;
> > +}
> > +
> >  static grub_err_t
> >  get_fs_root(struct grub_btrfs_data *data, grub_uint64_t tree,
> >              grub_uint64_t objectid, grub_uint64_t offset,
> > @@ -2892,6 +3079,7 @@ static struct grub_fs grub_btrfs_fs = {
> >  };
> >
> >  static grub_command_t cmd_info;
> > +static grub_command_t cmd_mount_subvol;
> >  static grub_extcmd_t cmd_list_subvols;
> >
> >  static char *
> > @@ -2955,6 +3143,9 @@ GRUB_MOD_INIT (btrfs)
> >    cmd_info = grub_register_command("btrfs-info", grub_cmd_btrfs_info,
> >                                    "DEVICE",
> >                                    "Print BtrFS info about DEVICE.");
> > +  cmd_mount_subvol = grub_register_command("btrfs-mount-subvol",
> > grub_cmd_btrfs_mount_subvol,
> > +                                  "DEVICE DIRECTORY SUBVOL",
> > +                                  "Set btrfs DEVICE the DIRECTORY a
> > mountpoint of SUBVOL.");
> >    cmd_list_subvols = grub_register_extcmd("btrfs-list-subvols",
> >                                          grub_cmd_btrfs_list_subvols, 0,
> >                                          "[-p|-n] [-o var] DEVICE",
> > diff --git a/grub-core/osdep/linux/getroot.c
> > b/grub-core/osdep/linux/getroot.c
> > index 7c29b3523..74a48c030 100644
> > --- a/grub-core/osdep/linux/getroot.c
> > +++ b/grub-core/osdep/linux/getroot.c
> > @@ -103,6 +103,14 @@ struct btrfs_ioctl_search_key
> >    grub_uint32_t unused[9];
> >  };
> >
> > +struct btrfs_ioctl_search_header {
> > +  grub_uint64_t transid;
> > +  grub_uint64_t objectid;
> > +  grub_uint64_t offset;
> > +  grub_uint32_t type;
> > +  grub_uint32_t len;
> > +};
> > +
> >  struct btrfs_ioctl_search_args {
> >    struct btrfs_ioctl_search_key key;
> >    grub_uint64_t buf[(4096 - sizeof(struct btrfs_ioctl_search_key))
> > @@ -375,6 +383,109 @@ get_btrfs_fs_prefix (const char *mount_path)
> >
> >  int use_relative_path_on_btrfs = 0;
> >
> > +static char *
> > +get_btrfs_subvol (const char *path)
> > +{
> > +  struct btrfs_ioctl_ino_lookup_args args;
> > +  grub_uint64_t tree_id;
> > +  int fd = -1;
> > +  char *ret = NULL;
> > +
> > +  fd = open (path, O_RDONLY);
> > +
> > +  if (fd < 0)
> > +    return NULL;
> > +
> > +  memset (&args, 0, sizeof(args));
> > +  args.objectid = GRUB_BTRFS_TREE_ROOT_OBJECTID;
> > +
> > +  if (ioctl (fd, BTRFS_IOC_INO_LOOKUP, &args) < 0)
> > +    goto error;
> > +
> > +  tree_id = args.treeid;
> > +
> > +  while (tree_id != GRUB_BTRFS_ROOT_VOL_OBJECTID)
> > +    {
> > +      struct btrfs_ioctl_search_args sargs;
> > +      struct grub_btrfs_root_backref *br;
> > +      struct btrfs_ioctl_search_header *search_header;
> > +      char *old;
> > +      grub_uint16_t len;
> > +      grub_uint64_t inode_id;
> > +
> > +      memset (&sargs, 0, sizeof(sargs));
> > +
> > +      sargs.key.tree_id = 1;
> > +      sargs.key.min_objectid = tree_id;
> > +      sargs.key.max_objectid = tree_id;
> > +
> > +      sargs.key.min_offset = 0;
> > +      sargs.key.max_offset = ~0ULL;
> > +      sargs.key.min_transid = 0;
> > +      sargs.key.max_transid = ~0ULL;
> > +      sargs.key.min_type = GRUB_BTRFS_ITEM_TYPE_ROOT_BACKREF;
> > +      sargs.key.max_type = GRUB_BTRFS_ITEM_TYPE_ROOT_BACKREF;
> > +
> > +      sargs.key.nr_items = 1;
> > +
> > +      if (ioctl (fd, BTRFS_IOC_TREE_SEARCH, &sargs) < 0)
> > +       goto error;
> > +
> > +      if (sargs.key.nr_items == 0)
> > +       goto error;
> > +
> > +      search_header = (struct btrfs_ioctl_search_header *)sargs.buf;
> > +      br = (struct grub_btrfs_root_backref *) (search_header + 1);
> > +
> > +      len = grub_le_to_cpu16 (br->n);
> > +      inode_id = grub_le_to_cpu64 (br->inode_id);
> > +      tree_id = search_header->offset;
> > +
> > +      old = ret;
> > +      ret = malloc (len + 1);
> > +      memcpy (ret, br->name, len);
> > +      ret[len] = '\0';
> > +
> > +      if (inode_id != GRUB_BTRFS_TREE_ROOT_OBJECTID)
> > +       {
> > +         char *s;
> > +
> > +         memset(&args, 0, sizeof(args));
> > +         args.treeid = search_header->offset;
> > +         args.objectid = inode_id;
> > +
> > +         if (ioctl (fd, BTRFS_IOC_INO_LOOKUP, &args) < 0)
> > +           goto error;
> > +
> > +         s = xasprintf ("%s%s", args.name, ret);
> > +         free (ret);
> > +         ret = s;
> > +       }
> > +
> > +      if (old)
> > +       {
> > +         char *s = xasprintf ("%s/%s", ret, old);
> > +         free (ret);
> > +         free (old);
> > +         ret = s;
> > +       }
> > +    }
> > +
> > +  close (fd);
> > +  return ret;
> > +
> > +error:
> > +
> > +  if (fd >= 0)
> > +    close (fd);
> > +  if (ret)
> > +    free (ret);
> > +
> > +  return NULL;
> > +}
> > +
> > +void (*grub_find_root_btrfs_mount_path_hook)(const char *mount_path);
> > +
> >  char **
> >  grub_find_root_devices_from_mountinfo (const char *dir, char **relroot)
> >  {
> > @@ -516,12 +627,15 @@ again:
> >        else if (grub_strcmp (entries[i].fstype, "btrfs") == 0)
> >         {
> >           ret = grub_find_root_devices_from_btrfs (dir);
> > -         fs_prefix = get_btrfs_fs_prefix (entries[i].enc_path);
> >           if (use_relative_path_on_btrfs)
> >             {
> > -             if (fs_prefix)
> > -               free (fs_prefix);
> >               fs_prefix = xstrdup ("/");
> > +             if (grub_find_root_btrfs_mount_path_hook)
> > +               grub_find_root_btrfs_mount_path_hook (entries[i].enc_path);
> > +           }
> > +         else
> > +           {
> > +             fs_prefix = get_btrfs_fs_prefix (entries[i].enc_path);
> >             }
> >         }
> >        else if (!retry && grub_strcmp (entries[i].fstype, "autofs") == 0)
> > @@ -1147,6 +1261,34 @@ grub_util_get_grub_dev_os (const char *os_dev)
> >    return grub_dev;
> >  }
> >
> > +
> > +char *
> > +grub_util_get_btrfs_subvol (const char *path, char **mount_path)
> > +{
> > +  char *mp = NULL;
> > +
> > +  if (mount_path)
> > +    *mount_path = NULL;
> > +
> > +  auto void
> > +  mount_path_hook (const char *m)
> > +  {
> > +    mp = strdup (m);
> > +  }
> > +
> > +  grub_find_root_btrfs_mount_path_hook = mount_path_hook;
> > +  grub_free (grub_find_root_devices_from_mountinfo (path, NULL));
> > +  grub_find_root_btrfs_mount_path_hook = NULL;
> > +
> > +  if (!mp)
> > +    return NULL;
> > +
> > +  if (mount_path)
> > +    *mount_path = mp;
> > +
> > +  return get_btrfs_subvol (mp);
> > +}
> > +
> >  char *
> >  grub_make_system_path_relative_to_its_root_os (const char *path)
> >  {
> > diff --git a/include/grub/emu/getroot.h b/include/grub/emu/getroot.h
> > index 73fa2d34a..9c642ae3f 100644
> > --- a/include/grub/emu/getroot.h
> > +++ b/include/grub/emu/getroot.h
> > @@ -53,6 +53,11 @@ char **
> >  grub_find_root_devices_from_mountinfo (const char *dir, char **relroot);
> >  #endif
> >
> > +#ifdef __linux__
> > +char *
> > +grub_util_get_btrfs_subvol (const char *path, char **mount_path);
> > +#endif
> > +
> >  /* Devmapper functions provided by getroot_devmapper.c.  */
> >  void
> >  grub_util_pull_devmapper (const char *os_dev);
> > diff --git a/util/grub-install.c b/util/grub-install.c
> > index ec3ed4967..d3ec2570d 100644
> > --- a/util/grub-install.c
> > +++ b/util/grub-install.c
> > @@ -1615,6 +1615,55 @@ main (int argc, char *argv[])
> >        prefix_drive = xasprintf ("(%s)", grub_drives[0]);
> >      }
> >
> > +#ifdef __linux__
> > +
> > +  if (config.is_suse_btrfs_snapshot_enabled
> > +      && grub_strncmp(grub_fs->name, "btrfs", sizeof ("btrfs") - 1) == 0)
> > +    {
> > +      char *subvol = NULL;
> > +      char *mount_path = NULL;
> > +      char **rootdir_devices = NULL;
> > +      char *rootdir_path = grub_util_path_concat (2, "/", rootdir);
> > +
> > +      if (grub_util_is_directory (rootdir_path))
> > +       rootdir_devices = grub_guess_root_devices (rootdir_path);
> > +
> > +      free (rootdir_path);
> > +
> > +      if (rootdir_devices && rootdir_devices[0])
> > +       if (grub_strcmp (rootdir_devices[0], grub_devices[0]) == 0)
> > +         subvol = grub_util_get_btrfs_subvol (platdir, &mount_path);
> > +
> > +      if (subvol && mount_path)
> > +       {
> > +         char *def_subvol;
> > +
> > +         def_subvol = grub_util_get_btrfs_subvol ("/", NULL);
> > +
> > +         if (def_subvol)
> > +           {
> > +             if (!load_cfg_f)
> > +               load_cfg_f = grub_util_fopen (load_cfg, "wb");
> > +             have_load_cfg = 1;
> > +
> > +             if (grub_strcmp (subvol, def_subvol) != 0)
> > +               fprintf (load_cfg_f, "btrfs-mount-subvol ($root) %s %s\n",
> > mount_path, subvol);
> > +             free (def_subvol);
> > +           }
> > +       }
> > +
> > +      for (curdev = rootdir_devices; *curdev; curdev++)
> > +       free (*curdev);
> > +      if (rootdir_devices)
> > +       free (rootdir_devices);
> > +      if (subvol)
> > +       free (subvol);
> > +      if (mount_path)
> > +       free (mount_path);
> > +    }
> > +
> > +#endif
> > +
> >    char mkimage_target[200];
> >    const char *core_name = NULL;
> >
> > --
> > 2.46.2
> >
> >
> > _______________________________________________
> > Grub-devel mailing list
> > Grub-devel@gnu.org
> > https://lists.gnu.org/mailman/listinfo/grub-devel
> >

> _______________________________________________
> Grub-devel mailing list
> Grub-devel@gnu.org
> https://lists.gnu.org/mailman/listinfo/grub-devel


_______________________________________________
Grub-devel mailing list
Grub-devel@gnu.org
https://lists.gnu.org/mailman/listinfo/grub-devel

Reply via email to