grub-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[PATCH v5 0/2] Introduce EROFS support


From: Yifan Zhao
Subject: [PATCH v5 0/2] Introduce EROFS support
Date: Mon, 4 Mar 2024 01:15:53 +0800

EROFS [1] is a lightweight read-only filesystem designed for performance
which has already been shipped in most Linux distributions as well as widely
used in several scenarios, such as Android system partitions, container
images, and rootfs for embedded devices.

This patch brings EROFS uncompressed support together with related tests.
Now, it's possible to boot directly through GRUB with an EROFS rootfs.

EROFS compressed files will be supported later since it has more work to
polish.

[1] https://erofs.docs.kernel.org

changelog since v4:
- correct the order of 'erofs-utils' in INSTALL
- fix format and alignment issue of #define
- use #define instead of enum for some constants
- fix incorrect usage of grub_off_t, use grub_uint64_t instead
- drop inline keyword for some functions
- 'if (err)' -> 'if (err != GRUB_ERR_NONE)'
- do not split lines slightly over 80 characters
- drop 'grub_' prefix for local functions in erofs module
- use safe math (and add bound check) for risky math operations
- other variable name and style changes according to Daniel's review

This interdiff shows the changes between v5 and v4 for easier review. In
addition, another interdiff between v4 and v2 (previous RVB version) is
provided to Glenn for reference.

Yifan Zhao (2):
  fs/erofs: Add support for EROFS
  fs/erofs: Add tests for EROFS in grub-fs-tester

 .gitignore                   |   1 +
 INSTALL                      |   8 +-
 Makefile.util.def            |   7 +
 docs/grub.texi               |   3 +-
 grub-core/Makefile.core.def  |   5 +
 grub-core/fs/erofs.c         | 978 +++++++++++++++++++++++++++++++++++
 grub-core/kern/misc.c        |  14 +
 include/grub/misc.h          |   1 +
 tests/erofs_test.in          |  20 +
 tests/util/grub-fs-tester.in |  32 +-
 10 files changed, 1057 insertions(+), 12 deletions(-)
 create mode 100644 grub-core/fs/erofs.c
 create mode 100644 tests/erofs_test.in

Interdiff against v4:
diff --git a/INSTALL b/INSTALL
index 545015ba2..84030c9f4 100644
--- a/INSTALL
+++ b/INSTALL
@@ -83,7 +83,7 @@ Prerequisites for make-check:
     exfat FUSE filesystem
 * The following are Debian named packages required mostly for the full
   suite of filesystem testing (but some are needed by other tests as well):
-  - btrfs-progs, dosfstools, erofs-utils, e2fsprogs, exfat-utils, f2fs-tools,
+  - btrfs-progs, dosfstools, e2fsprogs, erofs-utils, exfat-utils, f2fs-tools,
     genromfs, hfsprogs, jfsutils, nilfs-tools, ntfs-3g, reiserfsprogs,
     squashfs-tools, reiserfsprogs, udftools, xfsprogs, zfs-fuse
   - exfat-fuse, if not using the exfat kernel module
diff --git a/grub-core/fs/erofs.c b/grub-core/fs/erofs.c
index de57aaa5e..34f16ba20 100644
--- a/grub-core/fs/erofs.c
+++ b/grub-core/fs/erofs.c
@@ -1,7 +1,7 @@
 /* erofs.c - Enhanced Read-Only File System */
 /*
  *  GRUB  --  GRand Unified Bootloader
- *  Copyright (C) 2023 Free Software Foundation, Inc.
+ *  Copyright (C) 2024 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
@@ -30,12 +30,12 @@
 
 GRUB_MOD_LICENSE ("GPLv3+");
 
-#define EROFS_SUPER_OFFSET (1024)
+#define EROFS_SUPER_OFFSET     1024
 #define EROFS_MAGIC            0xE0F5E1E2
-#define EROFS_ISLOTBITS (5)
+#define EROFS_ISLOTBITS                5
 
 #define EROFS_FEATURE_INCOMPAT_CHUNKED_FILE    0x00000004
-#define EROFS_ALL_FEATURE_INCOMPAT (EROFS_FEATURE_INCOMPAT_CHUNKED_FILE)
+#define EROFS_ALL_FEATURE_INCOMPAT             
EROFS_FEATURE_INCOMPAT_CHUNKED_FILE
 
 struct grub_erofs_super
 {
@@ -53,7 +53,7 @@ struct grub_erofs_super
   grub_uint32_t blocks;
   grub_uint32_t meta_blkaddr;
   grub_uint32_t xattr_blkaddr;
-  grub_uint8_t uuid[16];
+  grub_packed_guid_t uuid;
   grub_uint8_t volume_name[16];
   grub_uint32_t feature_incompat;
 
@@ -75,15 +75,11 @@ struct grub_erofs_super
 #define EROFS_INODE_LAYOUT_COMPACT     0
 #define EROFS_INODE_LAYOUT_EXTENDED    1
 
-enum
-{
-  EROFS_INODE_FLAT_PLAIN = 0,
-  EROFS_INODE_COMPRESSED_FULL = 1,
-  EROFS_INODE_FLAT_INLINE = 2,
-  EROFS_INODE_COMPRESSED_COMPACT = 3,
-  EROFS_INODE_CHUNK_BASED = 4,
-  EROFS_INODE_DATALAYOUT_MAX
-};
+#define EROFS_INODE_FLAT_PLAIN         0
+#define EROFS_INODE_COMPRESSED_FULL    1
+#define EROFS_INODE_FLAT_INLINE                2
+#define EROFS_INODE_COMPRESSED_COMPACT 3
+#define EROFS_INODE_CHUNK_BASED                4
 
 #define EROFS_I_VERSION_MASKS          0x01
 #define EROFS_I_DATALAYOUT_MASKS       0x07
@@ -101,8 +97,11 @@ struct grub_erofs_inode_chunk_info
 #define EROFS_CHUNK_FORMAT_INDEXES     0x0020
 
 #define EROFS_BLOCK_MAP_ENTRY_SIZE     4
+#define EROFS_MAP_MAPPED               0x02
 
-#define EROFS_NULL_ADDR -1
+#define EROFS_NULL_ADDR                        1
+#define EROFS_NAME_LEN                 255
+#define EROFS_MAX_LOG2_BLOCK_SIZE      16
 
 struct grub_erofs_inode_chunk_index
 {
@@ -160,20 +159,14 @@ struct grub_erofs_inode_extended
   grub_uint8_t i_reserved2[16];
 } GRUB_PACKED;
 
-enum
-{
-  EROFS_FT_UNKNOWN,
-  EROFS_FT_REG_FILE,
-  EROFS_FT_DIR,
-  EROFS_FT_CHRDEV,
-  EROFS_FT_BLKDEV,
-  EROFS_FT_FIFO,
-  EROFS_FT_SOCK,
-  EROFS_FT_SYMLINK,
-  EROFS_FT_MAX
-};
-
-#define EROFS_NAME_LEN 255
+#define EROFS_FT_UNKNOWN       0
+#define EROFS_FT_REG_FILE      1
+#define EROFS_FT_DIR           2
+#define EROFS_FT_CHRDEV                3
+#define EROFS_FT_BLKDEV                4
+#define EROFS_FT_FIFO          5
+#define EROFS_FT_SOCK          6
+#define EROFS_FT_SYMLINK       7
 
 struct grub_erofs_dirent
 {
@@ -183,12 +176,12 @@ struct grub_erofs_dirent
   grub_uint8_t reserved;
 } GRUB_PACKED;
 
-#define EROFS_MAP_MAPPED 0x02
-
 struct grub_erofs_map_blocks
 {
-  grub_off_t m_pa, m_la;
-  grub_off_t m_plen, m_llen;
+  grub_uint64_t m_pa;
+  grub_uint64_t m_la;
+  grub_uint64_t m_plen;
+  grub_uint64_t m_llen;
   grub_uint32_t m_flags;
 };
 
@@ -210,7 +203,7 @@ struct grub_fshelp_node
   grub_uint8_t inode_datalayout;
 
   /* if the inode has been read into memory? */
-  bool inode_read;
+  bool inode_loaded;
 };
 
 struct grub_erofs_data
@@ -221,19 +214,18 @@ struct grub_erofs_data
   struct grub_fshelp_node inode;
 };
 
-#define erofs_blocksz(data) (1u << data->sb.log2_blksz)
+#define erofs_blocksz(data) (((grub_uint32_t) 1) << data->sb.log2_blksz)
 
-static inline grub_uint64_t
+static grub_uint64_t
 erofs_iloc (grub_fshelp_node_t node)
 {
   struct grub_erofs_super *sb = &node->data->sb;
 
-  return (grub_le_to_cpu32 (sb->meta_blkaddr) << sb->log2_blksz) +
-        (node->ino << EROFS_ISLOTBITS);
+  return (grub_le_to_cpu32 (sb->meta_blkaddr) << sb->log2_blksz) + (node->ino 
<< EROFS_ISLOTBITS);
 }
 
 static grub_err_t
-grub_erofs_read_inode (struct grub_erofs_data *data, grub_fshelp_node_t node)
+erofs_read_inode (struct grub_erofs_data *data, grub_fshelp_node_t node)
 {
   struct grub_erofs_inode_compact *dic;
   grub_err_t err;
@@ -244,13 +236,11 @@ grub_erofs_read_inode (struct grub_erofs_data *data, 
grub_fshelp_node_t node)
   err = grub_disk_read (data->disk, addr >> GRUB_DISK_SECTOR_BITS,
                        addr & (GRUB_DISK_SECTOR_SIZE - 1),
                        sizeof (struct grub_erofs_inode_compact), dic);
-  if (err)
+  if (err != GRUB_ERR_NONE)
     return err;
 
-  node->inode_type =
-      (dic->i_format >> EROFS_I_VERSION_BIT) & EROFS_I_VERSION_MASKS;
-  node->inode_datalayout =
-      (dic->i_format >> EROFS_I_DATALAYOUT_BIT) & EROFS_I_DATALAYOUT_MASKS;
+  node->inode_type = (dic->i_format >> EROFS_I_VERSION_BIT) & 
EROFS_I_VERSION_MASKS;
+  node->inode_datalayout = (dic->i_format >> EROFS_I_DATALAYOUT_BIT) & 
EROFS_I_DATALAYOUT_MASKS;
 
   switch (node->inode_type)
     {
@@ -259,26 +249,24 @@ grub_erofs_read_inode (struct grub_erofs_data *data, 
grub_fshelp_node_t node)
       err = grub_disk_read (
          data->disk, addr >> GRUB_DISK_SECTOR_BITS,
          addr & (GRUB_DISK_SECTOR_SIZE - 1),
-         sizeof (struct grub_erofs_inode_extended) -
-             sizeof (struct grub_erofs_inode_compact),
+         sizeof (struct grub_erofs_inode_extended) - sizeof (struct 
grub_erofs_inode_compact),
          (char *) dic + sizeof (struct grub_erofs_inode_compact));
-      if (err)
+      if (err != GRUB_ERR_NONE)
        return err;
       break;
     case EROFS_INODE_LAYOUT_COMPACT:
       break;
     default:
-      return grub_error (GRUB_ERR_BAD_FS,
-                        "invalid inode version %u @ inode %" PRIuGRUB_UINT64_T,
+      return grub_error (GRUB_ERR_BAD_FS, "invalid type %u @ inode %" 
PRIuGRUB_UINT64_T,
                         node->inode_type, node->ino);
     }
 
-  node->inode_read = true;
+  node->inode_loaded = true;
 
   return 0;
 }
 
-static inline grub_uint64_t
+static grub_uint64_t
 erofs_inode_size (grub_fshelp_node_t node)
 {
   return node->inode_type == EROFS_INODE_LAYOUT_COMPACT
@@ -286,28 +274,28 @@ erofs_inode_size (grub_fshelp_node_t node)
             : sizeof (struct grub_erofs_inode_extended);
 }
 
-static inline grub_uint64_t
+static grub_uint64_t
 erofs_inode_file_size (grub_fshelp_node_t node)
 {
-  struct grub_erofs_inode_compact *dic =
-      (struct grub_erofs_inode_compact *) &node->inode;
+  struct grub_erofs_inode_compact *dic = (struct grub_erofs_inode_compact *) 
&node->inode;
 
   return node->inode_type == EROFS_INODE_LAYOUT_COMPACT
             ? grub_le_to_cpu32 (dic->i_size)
             : grub_le_to_cpu64 (node->inode.i_size);
 }
 
-static inline grub_uint32_t
+static grub_uint32_t
 erofs_inode_xattr_ibody_size (grub_fshelp_node_t node)
 {
   grub_uint16_t cnt = grub_le_to_cpu16 (node->inode.i_xattr_icount);
 
-  return cnt ? sizeof (struct grub_erofs_xattr_ibody_header) +
-                  (cnt - 1) * sizeof (grub_uint32_t)
-            : 0;
+  if (cnt == 0)
+    return 0;
+
+  return sizeof (struct grub_erofs_xattr_ibody_header) + (cnt - 1) * sizeof 
(grub_uint32_t);
 }
 
-static inline grub_uint64_t
+static grub_uint64_t
 erofs_inode_mtime (grub_fshelp_node_t node)
 {
   return node->inode_type == EROFS_INODE_LAYOUT_COMPACT
@@ -316,31 +304,35 @@ erofs_inode_mtime (grub_fshelp_node_t node)
 }
 
 static grub_err_t
-grub_erofs_map_blocks_flatmode (grub_fshelp_node_t node,
+erofs_map_blocks_flatmode (grub_fshelp_node_t node,
                           struct grub_erofs_map_blocks *map)
 {
-  grub_off_t nblocks, lastblk, file_size;
-  grub_off_t tailendpacking =
-      (node->inode_datalayout == EROFS_INODE_FLAT_INLINE) ? 1 : 0;
+  grub_uint64_t nblocks, lastblk, file_size;
+  bool tailendpacking = (node->inode_datalayout == EROFS_INODE_FLAT_INLINE);
   grub_uint32_t blocksz = erofs_blocksz (node->data);
 
   file_size = erofs_inode_file_size (node);
   nblocks = (file_size + blocksz - 1) >> node->data->sb.log2_blksz;
-  lastblk = nblocks - tailendpacking;
+  lastblk = nblocks - (tailendpacking ? 1 : 0);
 
   map->m_flags = EROFS_MAP_MAPPED;
 
   if (map->m_la < (lastblk * blocksz))
     {
-      map->m_pa =
-         grub_le_to_cpu32 (node->inode.i_u.raw_blkaddr) * blocksz + map->m_la;
-      map->m_plen = lastblk * blocksz - map->m_la;
+      if (grub_mul (grub_le_to_cpu32 (node->inode.i_u.raw_blkaddr), blocksz, 
&map->m_pa) ||
+         grub_add (map->m_pa, map->m_la, &map->m_pa))
+       return GRUB_ERR_OUT_OF_RANGE;
+      if (grub_sub (lastblk * blocksz, map->m_la, &map->m_plen))
+       return GRUB_ERR_OUT_OF_RANGE;
     }
   else if (tailendpacking)
     {
-      map->m_pa = erofs_iloc (node) + erofs_inode_size (node) +
-                 erofs_inode_xattr_ibody_size (node) + (map->m_la % blocksz);
-      map->m_plen = file_size - map->m_la;
+      if (grub_add (erofs_iloc (node), erofs_inode_size (node), &map->m_pa) ||
+         grub_add (map->m_pa, erofs_inode_xattr_ibody_size (node), &map->m_pa) 
||
+         grub_add (map->m_pa, map->m_la % blocksz, &map->m_pa))
+       return GRUB_ERR_OUT_OF_RANGE;
+      if (grub_sub (file_size, map->m_la, &map->m_plen))
+       return GRUB_ERR_OUT_OF_RANGE;
 
       if (((map->m_pa % blocksz) + map->m_plen) > blocksz)
        return grub_error (
@@ -359,12 +351,11 @@ grub_erofs_map_blocks_flatmode (grub_fshelp_node_t node,
 }
 
 static grub_err_t
-grub_erofs_map_blocks_chunkmode (grub_fshelp_node_t node,
+erofs_map_blocks_chunkmode (grub_fshelp_node_t node,
                            struct grub_erofs_map_blocks *map)
 {
   grub_uint16_t chunk_format = grub_le_to_cpu16 (node->inode.i_u.c.format);
-  grub_off_t unit, pos;
-  grub_uint64_t chunknr;
+  grub_uint64_t unit, pos, chunknr;
   grub_uint8_t chunkbits;
   grub_err_t err;
 
@@ -373,19 +364,26 @@ grub_erofs_map_blocks_chunkmode (grub_fshelp_node_t node,
   else
     unit = EROFS_BLOCK_MAP_ENTRY_SIZE;
 
-  chunkbits = node->data->sb.log2_blksz +
-             (chunk_format & EROFS_CHUNK_FORMAT_BLKBITS_MASK);
+  chunkbits = node->data->sb.log2_blksz + (chunk_format & 
EROFS_CHUNK_FORMAT_BLKBITS_MASK);
+  if (chunkbits > 64)
+    return grub_error (GRUB_ERR_BAD_FS, "invalid chunkbits %u @ inode %" 
PRIuGRUB_UINT64_T,
+                      chunkbits, node->ino);
 
   chunknr = map->m_la >> chunkbits;
-  pos = ALIGN_UP (erofs_iloc (node) + erofs_inode_size (node) +
-                     erofs_inode_xattr_ibody_size (node),
-                 unit);
-  pos += chunknr * unit;
+
+  if (grub_add (erofs_iloc (node), erofs_inode_size (node), &pos) ||
+      grub_add (pos, erofs_inode_xattr_ibody_size (node), &pos))
+    return GRUB_ERR_OUT_OF_RANGE;
+  pos = ALIGN_UP (pos, unit);
+  if (grub_add (pos, chunknr * unit, &pos))
+    return GRUB_ERR_OUT_OF_RANGE;
 
   map->m_la = chunknr << chunkbits;
-  map->m_plen = grub_min (1ULL << chunkbits,
-                         ALIGN_UP (erofs_inode_file_size (node) - map->m_la,
-                                   erofs_blocksz (node->data)));
+
+  if (grub_sub (erofs_inode_file_size (node), map->m_la, &map->m_plen))
+    return GRUB_ERR_OUT_OF_RANGE;
+  map->m_plen = grub_min (((grub_uint64_t) 1) << chunkbits,
+                         ALIGN_UP (map->m_plen, erofs_blocksz (node->data)));
 
   if (chunk_format & EROFS_CHUNK_FORMAT_INDEXES)
     {
@@ -394,7 +392,7 @@ grub_erofs_map_blocks_chunkmode (grub_fshelp_node_t node,
 
       err = grub_disk_read (node->data->disk, pos >> GRUB_DISK_SECTOR_BITS,
                            pos & (GRUB_DISK_SECTOR_SIZE - 1), unit, &idx);
-      if (err)
+      if (err != GRUB_ERR_NONE)
        return err;
 
       blkaddr = grub_le_to_cpu32 (idx.blkaddr);
@@ -414,10 +412,9 @@ grub_erofs_map_blocks_chunkmode (grub_fshelp_node_t node,
     {
       grub_uint32_t blkaddr_le, blkaddr;
 
-      err =
-         grub_disk_read (node->data->disk, pos >> GRUB_DISK_SECTOR_BITS,
+      err = grub_disk_read (node->data->disk, pos >> GRUB_DISK_SECTOR_BITS,
                            pos & (GRUB_DISK_SECTOR_SIZE - 1), unit, 
&blkaddr_le);
-      if (err)
+      if (err != GRUB_ERR_NONE)
        return err;
 
       blkaddr = grub_le_to_cpu32 (blkaddr_le);
@@ -438,8 +435,7 @@ grub_erofs_map_blocks_chunkmode (grub_fshelp_node_t node,
 }
 
 static grub_err_t
-grub_erofs_map_blocks (grub_fshelp_node_t node,
-                      struct grub_erofs_map_blocks *map)
+erofs_map_blocks (grub_fshelp_node_t node, struct grub_erofs_map_blocks *map)
 {
   if (map->m_la >= erofs_inode_file_size (node))
     {
@@ -450,39 +446,38 @@ grub_erofs_map_blocks (grub_fshelp_node_t node,
     }
 
   if (node->inode_datalayout != EROFS_INODE_CHUNK_BASED)
-    return grub_erofs_map_blocks_flatmode (node, map);
+    return erofs_map_blocks_flatmode (node, map);
   else
-    return grub_erofs_map_blocks_chunkmode (node, map);
+    return erofs_map_blocks_chunkmode (node, map);
 }
 
 static grub_err_t
-grub_erofs_read_raw_data (grub_fshelp_node_t node, char *buf, grub_off_t size,
-                         grub_off_t offset, grub_off_t *bytes)
+erofs_read_raw_data (grub_fshelp_node_t node, char *buf, grub_uint64_t size,
+                    grub_uint64_t offset, grub_uint64_t *bytes)
 {
-  struct grub_erofs_map_blocks map;
+  struct grub_erofs_map_blocks map = {0};
+  grub_uint64_t cur;
   grub_err_t err;
 
   if (bytes)
     *bytes = 0;
 
-  if (!node->inode_read)
+  if (!node->inode_loaded)
     {
-      err = grub_erofs_read_inode (node->data, node);
-      if (err)
+      err = erofs_read_inode (node->data, node);
+      if (err != GRUB_ERR_NONE)
        return err;
     }
 
-  grub_memset (&map, 0, sizeof (map));
-
-  grub_off_t cur = offset;
+  cur = offset;
   while (cur < offset + size)
     {
       char *const estart = buf + cur - offset;
-      grub_off_t eend, moff = 0;
+      grub_uint64_t eend, moff = 0;
 
       map.m_la = cur;
-      err = grub_erofs_map_blocks (node, &map);
-      if (err)
+      err = erofs_map_blocks (node, &map);
+      if (err != GRUB_ERR_NONE)
        return err;
 
       eend = grub_min (offset + size, map.m_la + map.m_llen);
@@ -498,9 +493,9 @@ grub_erofs_read_raw_data (grub_fshelp_node_t node, char 
*buf, grub_off_t size,
 
          /* Hole */
          grub_memset (estart, 0, eend - cur);
-         cur = eend;
          if (bytes)
            *bytes += eend - cur;
+         cur = eend;
          continue;
        }
 
@@ -514,7 +509,7 @@ grub_erofs_read_raw_data (grub_fshelp_node_t node, char 
*buf, grub_off_t size,
                            (map.m_pa + moff) >> GRUB_DISK_SECTOR_BITS,
                            (map.m_pa + moff) & (GRUB_DISK_SECTOR_SIZE - 1),
                            eend - map.m_la, estart);
-      if (err)
+      if (err != GRUB_ERR_NONE)
        return err;
 
       if (bytes)
@@ -527,18 +522,18 @@ grub_erofs_read_raw_data (grub_fshelp_node_t node, char 
*buf, grub_off_t size,
 }
 
 static int
-grub_erofs_iterate_dir (grub_fshelp_node_t dir,
-                       grub_fshelp_iterate_dir_hook_t hook, void *hook_data)
+erofs_iterate_dir (grub_fshelp_node_t dir, grub_fshelp_iterate_dir_hook_t hook,
+                  void *hook_data)
 {
-  grub_off_t offset = 0, file_size;
-  grub_err_t err;
+  grub_uint64_t offset = 0, file_size;
   grub_uint32_t blocksz = erofs_blocksz (dir->data);
   char *buf;
+  grub_err_t err;
 
-  if (!dir->inode_read)
+  if (!dir->inode_loaded)
     {
-      err = grub_erofs_read_inode (dir->data, dir);
-      if (err)
+      err = erofs_read_inode (dir->data, dir);
+      if (err != GRUB_ERR_NONE)
        return 0;
     }
 
@@ -552,30 +547,30 @@ grub_erofs_iterate_dir (grub_fshelp_node_t dir,
 
   while (offset < file_size)
     {
-      grub_off_t maxsize = grub_min (blocksz, file_size - offset);
+      grub_uint64_t maxsize = grub_min (blocksz, file_size - offset);
       struct grub_erofs_dirent *de = (void *) buf, *end;
       grub_uint16_t nameoff;
 
-      err = grub_erofs_read_raw_data (dir, buf, maxsize, offset, NULL);
-      if (err)
+      err = erofs_read_raw_data (dir, buf, maxsize, offset, NULL);
+      if (err != GRUB_ERR_NONE)
        goto not_found;
 
       nameoff = grub_le_to_cpu16 (de->nameoff);
-      if (nameoff < sizeof (struct grub_erofs_dirent) || nameoff > blocksz)
+      if (nameoff < sizeof (struct grub_erofs_dirent) || nameoff > maxsize)
        {
          grub_error (GRUB_ERR_BAD_FS,
-                     "invalid de[0].nameoff %u @ inode %" PRIuGRUB_UINT64_T,
+                     "invalid nameoff %u @ inode %" PRIuGRUB_UINT64_T,
                      nameoff, dir->ino);
          goto not_found;
        }
 
-      end = (struct grub_erofs_dirent *) ((char *) de + nameoff);
+      end = (struct grub_erofs_dirent *) ((grub_uint8_t *) de + nameoff);
       while (de < end)
        {
          struct grub_fshelp_node *fdiro;
          enum grub_fshelp_filetype type;
          char filename[EROFS_NAME_LEN + 1];
-         unsigned int de_namelen;
+         grub_size_t de_namelen;
          const char *de_name;
 
          fdiro = grub_malloc (sizeof (struct grub_fshelp_node));
@@ -587,15 +582,32 @@ grub_erofs_iterate_dir (grub_fshelp_node_t dir,
 
          fdiro->data = dir->data;
          fdiro->ino = grub_le_to_cpu64 (de->nid);
-         fdiro->inode_read = false;
+         fdiro->inode_loaded = false;
 
          nameoff = grub_le_to_cpu16 (de->nameoff);
+         if (nameoff < sizeof (struct grub_erofs_dirent) || nameoff > maxsize)
+           {
+             grub_error (GRUB_ERR_BAD_FS,
+                         "invalid nameoff %u @ inode %" PRIuGRUB_UINT64_T,
+                         nameoff, dir->ino);
+             goto not_found;
+           }
+
          de_name = buf + nameoff;
          if (de + 1 >= end)
            de_namelen = grub_strnlen (de_name, maxsize - nameoff);
          else
            de_namelen = grub_le_to_cpu16 (de[1].nameoff) - nameoff;
 
+         if (nameoff + de_namelen > maxsize || de_namelen > EROFS_NAME_LEN)
+           {
+             grub_error (GRUB_ERR_BAD_FS,
+                         "invalid de_namelen %" PRIuGRUB_SIZE
+                         " @ inode %" PRIuGRUB_UINT64_T,
+                         de_namelen, dir->ino);
+             goto not_found;
+           }
+
          grub_memcpy (filename, de_name, de_namelen);
          filename[de_namelen] = '\0';
 
@@ -617,7 +629,6 @@ grub_erofs_iterate_dir (grub_fshelp_node_t dir,
            case EROFS_FT_UNKNOWN:
            default:
              type = GRUB_FSHELP_UNKNOWN;
-             break;
            }
 
          if (hook (filename, type, fdiro, hook_data))
@@ -638,15 +649,16 @@ not_found:
 }
 
 static char *
-grub_erofs_read_symlink (grub_fshelp_node_t node)
+erofs_read_symlink (grub_fshelp_node_t node)
 {
   char *symlink;
   grub_size_t sz;
+  grub_err_t err;
 
-  if (!node->inode_read)
+  if (!node->inode_loaded)
     {
-      grub_erofs_read_inode (node->data, node);
-      if (grub_errno)
+      err = erofs_read_inode (node->data, node);
+      if (err != GRUB_ERR_NONE)
        return NULL;
     }
 
@@ -660,8 +672,8 @@ grub_erofs_read_symlink (grub_fshelp_node_t node)
   if (!symlink)
     return NULL;
 
-  grub_erofs_read_raw_data (node, symlink, sz - 1, 0, NULL);
-  if (grub_errno)
+  err = erofs_read_raw_data (node, symlink, sz - 1, 0, NULL);
+  if (err != GRUB_ERR_NONE)
     {
       grub_free (symlink);
       return NULL;
@@ -672,7 +684,7 @@ grub_erofs_read_symlink (grub_fshelp_node_t node)
 }
 
 static struct grub_erofs_data *
-grub_erofs_mount (grub_disk_t disk, bool read_root)
+erofs_mount (grub_disk_t disk, bool read_root)
 {
   struct grub_erofs_super sb;
   grub_err_t err;
@@ -683,9 +695,10 @@ grub_erofs_mount (grub_disk_t disk, bool read_root)
                        sizeof (sb), &sb);
   if (grub_errno == GRUB_ERR_OUT_OF_RANGE)
     grub_error (GRUB_ERR_BAD_FS, "not a valid erofs filesystem");
-  if (err)
+  if (err != GRUB_ERR_NONE)
     return NULL;
-  if (sb.magic != grub_cpu_to_le32_compile_time (EROFS_MAGIC))
+  if (sb.magic != grub_cpu_to_le32_compile_time (EROFS_MAGIC) ||
+      grub_le_to_cpu32 (sb.log2_blksz) > EROFS_MAX_LOG2_BLOCK_SIZE)
     {
       grub_error (GRUB_ERR_BAD_FS, "not a valid erofs filesystem");
       return NULL;
@@ -713,8 +726,8 @@ grub_erofs_mount (grub_disk_t disk, bool read_root)
     {
       data->inode.data = data;
       data->inode.ino = grub_le_to_cpu16 (sb.root_nid);
-      err = grub_erofs_read_inode (data, &data->inode);
-      if (err)
+      err = erofs_read_inode (data, &data->inode);
+      if (err != GRUB_ERR_NONE)
        {
          grub_free (data);
          return NULL;
@@ -734,20 +747,19 @@ struct grub_erofs_dir_ctx
 
 /* Helper for grub_erofs_dir. */
 static int
-grub_erofs_dir_iter (const char *filename, enum grub_fshelp_filetype filetype,
+erofs_dir_iter (const char *filename, enum grub_fshelp_filetype filetype,
                grub_fshelp_node_t node, void *data)
 {
   struct grub_erofs_dir_ctx *ctx = data;
-  struct grub_dirhook_info info;
+  struct grub_dirhook_info info = {0};
 
-  grub_memset (&info, 0, sizeof (info));
-  if (!node->inode_read)
+  if (!node->inode_loaded)
     {
-      grub_erofs_read_inode (ctx->data, node);
+      erofs_read_inode (ctx->data, node);
       grub_errno = GRUB_ERR_NONE;
     }
 
-  if (node->inode_read)
+  if (node->inode_loaded)
     {
       info.mtimeset = 1;
       info.mtime = erofs_inode_mtime (node);
@@ -763,21 +775,22 @@ grub_erofs_dir (grub_device_t device, const char *path, 
grub_fs_dir_hook_t hook,
                void *hook_data)
 {
   grub_fshelp_node_t fdiro = NULL;
+  grub_err_t err;
   struct grub_erofs_dir_ctx ctx = {
       .hook = hook,
-      .hook_data = hook_data,
+      .hook_data = hook_data
   };
 
-  ctx.data = grub_erofs_mount (device->disk, true);
+  ctx.data = erofs_mount (device->disk, true);
   if (!ctx.data)
     goto fail;
 
-  grub_fshelp_find_file (path, &ctx.data->inode, &fdiro, 
grub_erofs_iterate_dir,
-                        grub_erofs_read_symlink, GRUB_FSHELP_DIR);
-  if (grub_errno)
+  err = grub_fshelp_find_file (path, &ctx.data->inode, &fdiro, 
erofs_iterate_dir,
+                              erofs_read_symlink, GRUB_FSHELP_DIR);
+  if (err != GRUB_ERR_NONE)
     goto fail;
 
-  grub_erofs_iterate_dir (fdiro, grub_erofs_dir_iter, &ctx);
+  erofs_iterate_dir (fdiro, erofs_dir_iter, &ctx);
 
  fail:
   if (fdiro != &ctx.data->inode)
@@ -794,23 +807,22 @@ grub_erofs_open (grub_file_t file, const char *name)
   struct grub_fshelp_node *fdiro = 0;
   grub_err_t err;
 
-  data = grub_erofs_mount (file->device->disk, true);
+  data = erofs_mount (file->device->disk, true);
   if (!data)
     {
       err = grub_errno;
       goto fail;
     }
 
-  err =
-      grub_fshelp_find_file (name, &data->inode, &fdiro, 
grub_erofs_iterate_dir,
-                            grub_erofs_read_symlink, GRUB_FSHELP_REG);
-  if (err)
+  err = grub_fshelp_find_file (name, &data->inode, &fdiro, erofs_iterate_dir,
+                              erofs_read_symlink, GRUB_FSHELP_REG);
+  if (err != GRUB_ERR_NONE)
     goto fail;
 
-  if (!fdiro->inode_read)
+  if (!fdiro->inode_loaded)
     {
-      err = grub_erofs_read_inode (data, fdiro);
-      if (err)
+      err = erofs_read_inode (data, fdiro);
+      if (err != GRUB_ERR_NONE)
        goto fail;
     }
 
@@ -835,39 +847,40 @@ grub_erofs_read (grub_file_t file, char *buf, grub_size_t 
len)
 {
   struct grub_erofs_data *data = file->data;
   struct grub_fshelp_node *inode = &data->inode;
-  grub_off_t off = file->offset, ret = 0;
-  grub_off_t file_size;
+  grub_off_t off = file->offset;
+  grub_uint64_t ret = 0, file_size;
+  grub_err_t err;
 
-  if (!inode->inode_read)
+  if (!inode->inode_loaded)
     {
-      grub_erofs_read_inode (data, inode);
-      if (grub_errno)
+      err = erofs_read_inode (data, inode);
+      if (err != GRUB_ERR_NONE)
        {
-         ret = 0;
-         grub_error (GRUB_ERR_IO, "cannot read @ inode %" PRIuGRUB_UINT64_T,
-                     inode->ino);
-         goto end;
+         grub_error (GRUB_ERR_IO, "cannot read @ inode %" PRIuGRUB_UINT64_T, 
inode->ino);
+         return -1;
        }
     }
 
   file_size = erofs_inode_file_size (inode);
 
-  if (off >= file_size)
-    goto end;
+  if (off > file_size)
+    {
+      grub_error (GRUB_ERR_IO, "read past EOF @ inode %" PRIuGRUB_UINT64_T, 
inode->ino);
+      return -1;
+    }
+  if (off == file_size)
+    return 0;
 
   if (off + len > file_size)
     len = file_size - off;
 
-  grub_erofs_read_raw_data (inode, buf, len, off, &ret);
-  if (grub_errno)
+  err = erofs_read_raw_data (inode, buf, len, off, &ret);
+  if (err != GRUB_ERR_NONE)
     {
-      ret = 0;
-      grub_error (GRUB_ERR_IO, "cannot read file @ inode %" PRIuGRUB_UINT64_T,
-                 inode->ino);
-      goto end;
+      grub_error (GRUB_ERR_IO, "cannot read file @ inode %" PRIuGRUB_UINT64_T, 
inode->ino);
+      return -1;
     }
 
-end:
   return ret;
 }
 
@@ -884,24 +897,18 @@ grub_erofs_uuid (grub_device_t device, char **uuid)
 {
   struct grub_erofs_data *data;
 
-  grub_errno = GRUB_ERR_NONE;
-  data = grub_erofs_mount (device->disk, false);
-
-  if (data)
-    *uuid = grub_xasprintf (
-       "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%"
-       "02x",
-       data->sb.uuid[0], data->sb.uuid[1], data->sb.uuid[2], data->sb.uuid[3],
-       data->sb.uuid[4], data->sb.uuid[5], data->sb.uuid[6], data->sb.uuid[7],
-       data->sb.uuid[8], data->sb.uuid[9], data->sb.uuid[10],
-       data->sb.uuid[11], data->sb.uuid[12], data->sb.uuid[13],
-       data->sb.uuid[14], data->sb.uuid[15]);
-  else
+  data = erofs_mount (device->disk, false);
+  if (!data)
+    {
       *uuid = NULL;
+      return grub_errno;
+    }
+
+  *uuid = grub_xasprintf ("%pG", &data->sb.uuid);
 
   grub_free (data);
 
-  return grub_errno;
+  return GRUB_ERR_NONE;
 }
 
 static grub_err_t
@@ -909,18 +916,20 @@ grub_erofs_label (grub_device_t device, char **label)
 {
   struct grub_erofs_data *data;
 
-  grub_errno = GRUB_ERR_NONE;
-  data = grub_erofs_mount (device->disk, false);
-
-  if (data)
-    *label = grub_strndup ((char *) data->sb.volume_name,
-                          sizeof (data->sb.volume_name));
-  else
+  data = erofs_mount (device->disk, false);
+  if (!data)
+    {
       *label = NULL;
+      return grub_errno;
+    }
+
+  *label = grub_strndup ((char *) data->sb.volume_name, sizeof 
(data->sb.volume_name));
+  if (!*label)
+    return grub_errno;
 
   grub_free (data);
 
-  return grub_errno;
+  return GRUB_ERR_NONE;
 }
 
 static grub_err_t
@@ -928,17 +937,18 @@ grub_erofs_mtime (grub_device_t device, grub_int64_t *tm)
 {
   struct grub_erofs_data *data;
 
-  grub_errno = GRUB_ERR_NONE;
-  data = grub_erofs_mount (device->disk, false);
-
+  data = erofs_mount (device->disk, false);
   if (!data)
+    {
       *tm = 0;
-  else
+      return grub_errno;
+    }
+
   *tm = grub_le_to_cpu64 (data->sb.build_time);
 
   grub_free (data);
 
-  return grub_errno;
+  return GRUB_ERR_NONE;
 }
 
 static struct grub_fs grub_erofs_fs = {
-- 
2.44.0




reply via email to

[Prev in Thread] Current Thread [Next in Thread]