grub-devel.gnu.org archive mirror
 help / color / mirror / Atom feed
From: Yifan Zhao <zhaoyifan@sjtu.edu.cn>
To: dkiper@net-space.pl, development@efficientek.com
Cc: grub-devel@gnu.org, hsiangkao@linux.alibaba.com, zhaoyifan@sjtu.edu.cn
Subject: [PATCH v5 0/2] Introduce EROFS support
Date: Mon,  4 Mar 2024 01:15:53 +0800	[thread overview]
Message-ID: <20240303171558.800691-1-zhaoyifan@sjtu.edu.cn> (raw)

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


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

             reply	other threads:[~2024-03-03 17:17 UTC|newest]

Thread overview: 14+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2024-03-03 17:15 Yifan Zhao [this message]
2024-03-03 17:15 ` [PATCH v5 1/2] fs/erofs: Add support for EROFS Yifan Zhao
2024-03-06  2:18   ` Gao Xiang
2024-04-04 20:56     ` Daniel Kiper
2024-04-10 11:23       ` Gao Xiang
2024-04-18  8:16   ` Glenn Washburn
2024-04-18 17:12     ` Yifan Zhao
2024-04-22  3:15       ` Glenn Washburn
2024-04-22  3:35         ` Yifan Zhao
2024-04-22  4:20         ` Yifan Zhao
2024-04-27  6:42           ` Glenn Washburn
2024-03-03 17:15 ` [PATCH v5 2/2] fs/erofs: Add tests for EROFS in grub-fs-tester Yifan Zhao
2024-04-18  8:19   ` Glenn Washburn
2024-03-03 17:17 ` [PATCH v4~v2 Interdiff] Introduce EROFS support Yifan Zhao

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20240303171558.800691-1-zhaoyifan@sjtu.edu.cn \
    --to=zhaoyifan@sjtu.edu.cn \
    --cc=development@efficientek.com \
    --cc=dkiper@net-space.pl \
    --cc=grub-devel@gnu.org \
    --cc=hsiangkao@linux.alibaba.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).