Linux-EROFS Archive on lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 0/8] erofs-utils: fix issues found by LLMs
@ 2026-11-12 12:47 Yifan Zhao
  2026-11-12 12:47 ` [PATCH 1/8] erofs-utils: lib: fix arithmetic overflow in large file handling Yifan Zhao
                   ` (7 more replies)
  0 siblings, 8 replies; 11+ messages in thread
From: Yifan Zhao @ 2026-11-12 12:47 UTC (permalink / raw)
  To: linux-erofs; +Cc: Yifan Zhao

This series fixes several code issues identified by LLMs. All findings
have been manually analyzed and reviewed.

Yifan Zhao (8):
  erofs-utils: lib: fix arithmetic overflow in large file handling
  erofs-utils: mkfs: fix incremental superblock stack overread
  erofs-utils: tar: fix out-of-bounds access when trimming PAX paths
  erofs-utils: lib: fix buffer leaks in error paths
  erofs-utils: exclude: fix stack overflow when checking long paths
  erofs-utils: lib: fix gzran EOF handling and state leaks
  erofs-utils: lib: fix metabox inline data reads
  erofs-utils: fix read error and short read handling

 lib/backends/fanotify.c |  3 ++-
 lib/backends/nbd.c      |  2 ++
 lib/backends/ublk.c     |  2 +-
 lib/compress.c          |  6 ++++--
 lib/data.c              | 28 ++++++++++++++--------------
 lib/exclude.c           |  7 ++++++-
 lib/fragments.c         | 10 +++-------
 lib/gzran.c             | 27 +++++++++++++++++----------
 lib/inode.c             | 19 ++++++++++++-------
 lib/rebuild.c           |  2 +-
 lib/remotes/oci.c       |  1 +
 lib/super.c             |  8 +++++++-
 lib/tar.c               |  6 +++++-
 mount/main.c            | 10 +++++-----
 14 files changed, 80 insertions(+), 51 deletions(-)

-- 
2.56.0



^ permalink raw reply	[flat|nested] 11+ messages in thread

* [PATCH 1/8] erofs-utils: lib: fix arithmetic overflow in large file handling
  2026-11-12 12:47 [PATCH 0/8] erofs-utils: fix issues found by LLMs Yifan Zhao
@ 2026-11-12 12:47 ` Yifan Zhao
  2026-11-12 12:47 ` [PATCH 2/8] erofs-utils: mkfs: fix incremental superblock stack overread Yifan Zhao
                   ` (6 subsequent siblings)
  7 siblings, 0 replies; 11+ messages in thread
From: Yifan Zhao @ 2026-11-12 12:47 UTC (permalink / raw)
  To: linux-erofs; +Cc: Yifan Zhao

Assisted-by: Codex:gpt-6-astra
Assisted-by: Claude Code:deepseek-v4.1-flash-1017
Signed-off-by: Yifan Zhao <stopire@gmail.com>
---
 lib/compress.c | 2 +-
 lib/rebuild.c  | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/lib/compress.c b/lib/compress.c
index b079558..e1cfc05 100644
--- a/lib/compress.c
+++ b/lib/compress.c
@@ -560,7 +560,7 @@ static bool z_erofs_fixup_deduped_fragment(struct z_erofs_compress_sctx *ctx)
 	struct z_erofs_compress_ictx *ictx = ctx->ictx;
 	struct erofs_inode *inode = ictx->inode;
 	struct erofs_sb_info *sbi = inode->sbi;
-	const unsigned int newsize = ctx->remaining + ctx->tail - ctx->head;
+	const erofs_off_t newsize = ctx->remaining + ctx->tail - ctx->head;
 
 	DBG_BUGON(!inode->fragment_size);
 
diff --git a/lib/rebuild.c b/lib/rebuild.c
index 94dc66d..2fa8feb 100644
--- a/lib/rebuild.c
+++ b/lib/rebuild.c
@@ -262,7 +262,7 @@ static int erofs_rebuild_load_chunk_index(struct erofs_sb_info *dst_sb,
 			.buf = __EROFS_BUF_INITIALIZER,
 		};
 
-		map.m_la = i << chunkbits;
+		map.m_la = (erofs_off_t)i << chunkbits;
 		ret = erofs_map_blocks(inode, &map, 0);
 		if (ret)
 			goto err;
-- 
2.56.0



^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [PATCH 2/8] erofs-utils: mkfs: fix incremental superblock stack overread
  2026-11-12 12:47 [PATCH 0/8] erofs-utils: fix issues found by LLMs Yifan Zhao
  2026-11-12 12:47 ` [PATCH 1/8] erofs-utils: lib: fix arithmetic overflow in large file handling Yifan Zhao
@ 2026-11-12 12:47 ` Yifan Zhao
  2026-11-12 12:47 ` [PATCH 3/8] erofs-utils: tar: fix out-of-bounds access when trimming PAX paths Yifan Zhao
                   ` (5 subsequent siblings)
  7 siblings, 0 replies; 11+ messages in thread
From: Yifan Zhao @ 2026-11-12 12:47 UTC (permalink / raw)
  To: linux-erofs; +Cc: Yifan Zhao

Running mkfs.erofs --incremental on a base image with sb_extslots > 1
retains a superblock size larger than the 144-byte stack object in
erofs_writesb(). The final memcpy() reads past that object and writes
adjacent stack contents into the image.

Trigger path:
  main()
    erofs_mkfs_load_fs()
      erofs_read_superblock()  /* sb_size = 128 + sb_extslots * 16 */
    erofs_writesb()
      memcpy(..., &sb, sbi->sb_size)

Let's limit the source image sb size in incremental builds.

Fixes: c6903c7e32a1 ("erofs-utils: dump,fsck,fuse: support metadata compression")
Assisted-by: Codex:gpt-6-astra
Assisted-by: Claude Code:deepseek-v4.1-flash-1017
Signed-off-by: Yifan Zhao <stopire@gmail.com>
---
 lib/super.c | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/lib/super.c b/lib/super.c
index 5cb9016..694a3e9 100644
--- a/lib/super.c
+++ b/lib/super.c
@@ -515,6 +515,12 @@ int erofs_mkfs_load_fs(struct erofs_sb_info *sbi, unsigned int dsunit)
 		return err;
 	}
 
+	if (sbi->sb_size > sizeof(struct erofs_super_block)) {
+		erofs_err("unsupported superblock size %u for incremental builds",
+			  sbi->sb_size);
+		return -EOPNOTSUPP;
+	}
+
 	err = erofs_io_fstat(&sbi->bdev, &u.st);
 	if (!err && S_ISREG(u.st.st_mode))
 		u.startblk = DIV_ROUND_UP(u.st.st_size, erofs_blksiz(sbi));
-- 
2.56.0



^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [PATCH 3/8] erofs-utils: tar: fix out-of-bounds access when trimming PAX paths
  2026-11-12 12:47 [PATCH 0/8] erofs-utils: fix issues found by LLMs Yifan Zhao
  2026-11-12 12:47 ` [PATCH 1/8] erofs-utils: lib: fix arithmetic overflow in large file handling Yifan Zhao
  2026-11-12 12:47 ` [PATCH 2/8] erofs-utils: mkfs: fix incremental superblock stack overread Yifan Zhao
@ 2026-11-12 12:47 ` Yifan Zhao
  2026-11-12 12:47 ` [PATCH 4/8] erofs-utils: lib: fix buffer leaks in error paths Yifan Zhao
                   ` (4 subsequent siblings)
  7 siblings, 0 replies; 11+ messages in thread
From: Yifan Zhao @ 2026-11-12 12:47 UTC (permalink / raw)
  To: linux-erofs; +Cc: Yifan Zhao

An embedded NUL in a PAX path makes strdup() allocate less space than
the record length used to trim trailing slashes, causing out-of-bounds
accesses.

Use strlen() for the trim length and handle strdup() failures.

Assisted-by: Codex:gpt-6-astra
Assisted-by: Claude Code:deepseek-v4.1-flash-1017
Signed-off-by: Yifan Zhao <stopire@gmail.com>
---
 lib/tar.c | 6 +++++-
 1 file changed, 5 insertions(+), 1 deletion(-)

diff --git a/lib/tar.c b/lib/tar.c
index f5034da..bab855f 100644
--- a/lib/tar.c
+++ b/lib/tar.c
@@ -527,8 +527,12 @@ int tarerofs_parse_pax_header(struct erofs_iostream *ios,
 					eh->path = NULL;
 					continue;
 				}
-				j = p - 1 - value;
 				eh->path = strdup(value);
+				if (!eh->path) {
+					ret = -ENOMEM;
+					goto out;
+				}
+				j = strlen(eh->path);
 				while (j && eh->path[j - 1] == '/')
 					eh->path[--j] = '\0';
 			} else if (!strncmp(kv, "linkpath=",
-- 
2.56.0



^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [PATCH 4/8] erofs-utils: lib: fix buffer leaks in error paths
  2026-11-12 12:47 [PATCH 0/8] erofs-utils: fix issues found by LLMs Yifan Zhao
                   ` (2 preceding siblings ...)
  2026-11-12 12:47 ` [PATCH 3/8] erofs-utils: tar: fix out-of-bounds access when trimming PAX paths Yifan Zhao
@ 2026-11-12 12:47 ` Yifan Zhao
  2026-11-12 23:20   ` Gao Xiang
  2026-11-12 12:47 ` [PATCH 5/8] erofs-utils: exclude: fix stack overflow when checking long paths Yifan Zhao
                   ` (3 subsequent siblings)
  7 siblings, 1 reply; 11+ messages in thread
From: Yifan Zhao @ 2026-11-12 12:47 UTC (permalink / raw)
  To: linux-erofs; +Cc: Yifan Zhao

Fragment data is already written before its buffer is shrunk.
A failed realloc() should leave the original buffer valid, so the
fragment commit can continue without shrinking it.

Also fix an inline data buffer leak when loading compressed metadata
fails during rebuild.

Fixes: 84bae6acdbee ("erofs-utils: lib: keep full data until the fragment is committed")
Fixes: 1c230a485f25 ("erofs-utils: mkfs: support rebuild mode for compressed inodes")
Assisted-by: Codex:gpt-6-astra
Assisted-by: Claude Code:deepseek-v4.1-flash-1017
Signed-off-by: Yifan Zhao <stopire@gmail.com>
---
 lib/compress.c  | 2 ++
 lib/fragments.c | 8 ++------
 2 files changed, 4 insertions(+), 6 deletions(-)

diff --git a/lib/compress.c b/lib/compress.c
index e1cfc05..b5f75ca 100644
--- a/lib/compress.c
+++ b/lib/compress.c
@@ -2607,6 +2607,8 @@ int z_erofs_rebuild_load_metadata(struct erofs_sb_info *dst_sbi,
 err_free_ei:
 	free(ei);
 err_out:
+	free(inode->idata);
+	inode->idata = NULL;
 	list_for_each_entry_safe(ei, n, &extents, list) {
 		list_del(&ei->list);
 		free(ei);
diff --git a/lib/fragments.c b/lib/fragments.c
index d4e79b2..3398888 100644
--- a/lib/fragments.c
+++ b/lib/fragments.c
@@ -366,12 +366,8 @@ int erofs_fragment_commit(struct erofs_inode *inode, u32 tofh)
 		memmove(fi->data, fi->data + fi->length - sz, sz);
 
 		nb = realloc(fi->data, sz);
-		if (!nb) {
-			erofs_up_write(&bk->lock);
-			fi->data = NULL;
-			return -ENOMEM;
-		}
-		fi->data = nb;
+		if (nb)
+			fi->data = nb;
 		fi->pos = (erofs_off_t)offset;
 		erofs_up_write(&bk->lock);
 		inode->fragmentoff = fi->pos - len;
-- 
2.56.0



^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [PATCH 5/8] erofs-utils: exclude: fix stack overflow when checking long paths
  2026-11-12 12:47 [PATCH 0/8] erofs-utils: fix issues found by LLMs Yifan Zhao
                   ` (3 preceding siblings ...)
  2026-11-12 12:47 ` [PATCH 4/8] erofs-utils: lib: fix buffer leaks in error paths Yifan Zhao
@ 2026-11-12 12:47 ` Yifan Zhao
  2026-11-12 12:47 ` [PATCH 6/8] erofs-utils: lib: fix gzran EOF handling and state leaks Yifan Zhao
                   ` (2 subsequent siblings)
  7 siblings, 0 replies; 11+ messages in thread
From: Yifan Zhao @ 2026-11-12 12:47 UTC (permalink / raw)
  To: linux-erofs; +Cc: Yifan Zhao

Assisted-by: Codex:gpt-6-astra
Assisted-by: Claude Code:deepseek-v4.1-flash-1017
Signed-off-by: Yifan Zhao <stopire@gmail.com>
---
 lib/exclude.c | 7 ++++++-
 lib/inode.c   | 8 +++++++-
 2 files changed, 13 insertions(+), 2 deletions(-)

diff --git a/lib/exclude.c b/lib/exclude.c
index 6beb46b..487da6a 100644
--- a/lib/exclude.c
+++ b/lib/exclude.c
@@ -108,7 +108,12 @@ struct erofs_exclude_rule *erofs_is_exclude_path(const char *dir,
 		/* no prefix */
 		s = name;
 	} else {
-		sprintf(buf, "%s/%s", dir, name);
+		int ret = snprintf(buf, sizeof(buf), "%s/%s", dir, name);
+
+		if (ret < 0)
+			return ERR_PTR(-errno);
+		if ((size_t)ret >= sizeof(buf))
+			return ERR_PTR(-ENAMETOOLONG);
 		s = buf;
 	}
 
diff --git a/lib/inode.c b/lib/inode.c
index 3108aa0..f687857 100644
--- a/lib/inode.c
+++ b/lib/inode.c
@@ -1851,6 +1851,7 @@ static int erofs_mkfs_import_localdir(struct erofs_importer *im, struct erofs_in
 	__nr_subdirs = *nr_subdirs;
 	__nlink = *i_nlink;
 	while (1) {
+		struct erofs_exclude_rule *rule;
 		struct erofs_inode *inode;
 		struct erofs_dentry *d;
 		char buf[PATH_MAX];
@@ -1873,7 +1874,12 @@ static int erofs_mkfs_import_localdir(struct erofs_importer *im, struct erofs_in
 			continue;
 
 		/* skip if it's a exclude file */
-		if (erofs_is_exclude_path(dir->i_srcpath, dp->d_name))
+		rule = erofs_is_exclude_path(dir->i_srcpath, dp->d_name);
+		if (IS_ERR(rule)) {
+			ret = PTR_ERR(rule);
+			goto err_closedir;
+		}
+		if (rule)
 			continue;
 
 		d = erofs_d_alloc(dir, dp->d_name);
-- 
2.56.0



^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [PATCH 6/8] erofs-utils: lib: fix gzran EOF handling and state leaks
  2026-11-12 12:47 [PATCH 0/8] erofs-utils: fix issues found by LLMs Yifan Zhao
                   ` (4 preceding siblings ...)
  2026-11-12 12:47 ` [PATCH 5/8] erofs-utils: exclude: fix stack overflow when checking long paths Yifan Zhao
@ 2026-11-12 12:47 ` Yifan Zhao
  2026-11-12 12:47 ` [PATCH 7/8] erofs-utils: lib: fix metabox inline data reads Yifan Zhao
  2026-11-12 12:47 ` [PATCH 8/8] erofs-utils: fix read error and short read handling Yifan Zhao
  7 siblings, 0 replies; 11+ messages in thread
From: Yifan Zhao @ 2026-11-12 12:47 UTC (permalink / raw)
  To: linux-erofs; +Cc: Yifan Zhao

An initial EOF can produce an invalid inflate input length, and the
state allocated by inflateInit2() is never freed.

Let's reject initial EOF with -EIO and call inflateEnd() on all exits
after successful initialization.

Fixes: 80b2ba447fb0 ("erofs-utils: lib: add gzran virtual file support")
Assisted-by: Codex:gpt-6-astra
Assisted-by: Claude Code:deepseek-v4.1-flash-1017
Signed-off-by: Yifan Zhao <stopire@gmail.com>
---
 lib/gzran.c | 27 +++++++++++++++++----------
 1 file changed, 17 insertions(+), 10 deletions(-)

diff --git a/lib/gzran.c b/lib/gzran.c
index a75756c..dcc4497 100644
--- a/lib/gzran.c
+++ b/lib/gzran.c
@@ -231,7 +231,7 @@ static ssize_t erofs_gzran_ios_vfpread(struct erofs_vfile *vf, void *buf, size_t
 	bool skip = true;
 	u64 inpos, remin;
 	z_stream strm;
-	int ret;
+	ssize_t ret;
 
 	if (offset == ~0ULL) {
 		DBG_BUGON(1);
@@ -257,8 +257,10 @@ static ssize_t erofs_gzran_ios_vfpread(struct erofs_vfile *vf, void *buf, size_t
 	remin -= inpos;
 	ret = erofs_io_pread(ios->vin, src,
 			     min(remin, (u64)sizeof(src)), inpos);
-	if (ret < 0)
-		return ret;
+	if (ret <= 0) {
+		ret = ret < 0 ? ret : -EIO;
+		goto out;
+	}
 	if (u.bits) {
 		inflatePrime(&strm, u.bits, src[0] >> (8 - u.bits));
 		strm.next_in = src + 1;
@@ -294,10 +296,10 @@ static ssize_t erofs_gzran_ios_vfpread(struct erofs_vfile *vf, void *buf, size_t
 				ret = erofs_io_pread(ios->vin, src,
 						     min(remin, (u64)sizeof(src)),
 						     inpos);
-				if (ret < 0)
-					return ret;
-				if (!ret)
-					return -EIO;
+				if (ret <= 0) {
+					ret = ret < 0 ? ret : -EIO;
+					goto out;
+				}
 				inpos += ret;
 				remin -= ret;
 				strm.avail_in = ret;
@@ -306,8 +308,10 @@ static ssize_t erofs_gzran_ios_vfpread(struct erofs_vfile *vf, void *buf, size_t
 			ret = inflate(&strm, Z_NO_FLUSH);       /* normal inflate */
 			if (ret == Z_NEED_DICT)
 				ret = Z_DATA_ERROR;
-			if (ret == Z_MEM_ERROR || ret == Z_DATA_ERROR)
-				return -EIO;
+			if (ret == Z_MEM_ERROR || ret == Z_DATA_ERROR) {
+				ret = -EIO;
+				goto out;
+			}
 			if (ret == Z_STREAM_END)
 				break;
 		} while (strm.avail_out);
@@ -318,7 +322,10 @@ static ssize_t erofs_gzran_ios_vfpread(struct erofs_vfile *vf, void *buf, size_t
 
 		/* do until offset reached and requested data read, or stream ends */
 	} while (skip);
-	return len - strm.avail_out;
+	ret = len - strm.avail_out;
+out:
+	inflateEnd(&strm);
+	return ret;
 }
 
 static struct erofs_vfops erofs_gzran_ios_vfops = {
-- 
2.56.0



^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [PATCH 7/8] erofs-utils: lib: fix metabox inline data reads
  2026-11-12 12:47 [PATCH 0/8] erofs-utils: fix issues found by LLMs Yifan Zhao
                   ` (5 preceding siblings ...)
  2026-11-12 12:47 ` [PATCH 6/8] erofs-utils: lib: fix gzran EOF handling and state leaks Yifan Zhao
@ 2026-11-12 12:47 ` Yifan Zhao
  2026-11-12 12:47 ` [PATCH 8/8] erofs-utils: fix read error and short read handling Yifan Zhao
  7 siblings, 0 replies; 11+ messages in thread
From: Yifan Zhao @ 2026-11-12 12:47 UTC (permalink / raw)
  To: linux-erofs; +Cc: Yifan Zhao

fsck reads inline data in metabox through:

  erofs_verify_inode_data()
          |
          v
  erofs_read_one_data()
          |
          v
  erofs_dev_read()  <-- metabox offset used as physical image offset

Let's move metabox inline data handling from erofs_read_raw_data()
to erofs_read_one_data().

Fixes: c6903c7e32a1 ("erofs-utils: dump,fsck,fuse: support metadata compression")
Assisted-by: Codex:gpt-6-astra
Assisted-by: Claude Code:deepseek-v4.1-flash-1017
Signed-off-by: Yifan Zhao <stopire@gmail.com>
---
 lib/data.c | 28 ++++++++++++++--------------
 1 file changed, 14 insertions(+), 14 deletions(-)

diff --git a/lib/data.c b/lib/data.c
index c73cbe3..91809d0 100644
--- a/lib/data.c
+++ b/lib/data.c
@@ -215,6 +215,19 @@ int erofs_read_one_data(struct erofs_inode *inode, struct erofs_map_blocks *map,
 	struct erofs_map_dev mdev;
 	int ret;
 
+	if ((map->m_flags & EROFS_MAP_META) &&
+	    erofs_inode_in_metabox(inode)) {
+		struct erofs_buf buf = __EROFS_BUF_INITIALIZER;
+		void *src;
+
+		src = erofs_read_metabuf(&buf, sbi, map->m_pa + offset, true);
+		if (IS_ERR(src))
+			return PTR_ERR(src);
+		memcpy(buffer, src, len);
+		erofs_put_metabuf(&buf);
+		return 0;
+	}
+
 	mdev = (struct erofs_map_dev) {
 		.m_deviceid = map->m_deviceid,
 		.m_pa = map->m_pa,
@@ -253,20 +266,7 @@ static int erofs_read_raw_data(struct erofs_inode *inode, char *buffer,
 		eend = min(offset + size, map.m_la + map.m_llen);
 		DBG_BUGON(ptr < map.m_la);
 
-		if ((map.m_flags & EROFS_MAP_META) &&
-		    erofs_inode_in_metabox(inode)) {
-			struct erofs_buf buf = __EROFS_BUF_INITIALIZER;
-			void *src;
-
-			src = erofs_read_metabuf(&buf, inode->sbi,
-						 map.m_pa, true);
-			if (IS_ERR(src))
-				return PTR_ERR(src);
-			memcpy(estart, src, eend - ptr);
-			erofs_put_metabuf(&buf);
-			ptr = eend;
-			continue;
-		} else if (!(map.m_flags & EROFS_MAP_MAPPED)) {
+		if (!(map.m_flags & EROFS_MAP_MAPPED)) {
 			if (!map.m_llen) {
 				/* reached EOF */
 				memset(estart, 0, offset + size - ptr);
-- 
2.56.0



^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [PATCH 8/8] erofs-utils: fix read error and short read handling
  2026-11-12 12:47 [PATCH 0/8] erofs-utils: fix issues found by LLMs Yifan Zhao
                   ` (6 preceding siblings ...)
  2026-11-12 12:47 ` [PATCH 7/8] erofs-utils: lib: fix metabox inline data reads Yifan Zhao
@ 2026-11-12 12:47 ` Yifan Zhao
  2026-11-12 23:41   ` Gao Xiang
  7 siblings, 1 reply; 11+ messages in thread
From: Yifan Zhao @ 2026-11-12 12:47 UTC (permalink / raw)
  To: linux-erofs; +Cc: Yifan Zhao

Several erofs_io_read() and erofs_io_pread() callers mishandle negative
errors or unexpected short reads, potentially reporting success or
looping at EOF.

Propagate negative errors, reject unexpected short reads and premature
EOF, and preserve the result reported by the ublk handler.

Also cap OCI blob copies at the requested length.

Assisted-by: Codex:gpt-6-astra
Assisted-by: Claude Code:deepseek-v4.1-flash-1017
Signed-off-by: Yifan Zhao <stopire@gmail.com>
---
 lib/backends/fanotify.c |  3 ++-
 lib/backends/nbd.c      |  2 ++
 lib/backends/ublk.c     |  2 +-
 lib/compress.c          |  2 +-
 lib/fragments.c         |  2 +-
 lib/inode.c             | 11 +++++------
 lib/remotes/oci.c       |  1 +
 lib/super.c             |  2 +-
 mount/main.c            | 10 +++++-----
 9 files changed, 19 insertions(+), 16 deletions(-)

diff --git a/lib/backends/fanotify.c b/lib/backends/fanotify.c
index cf8b616..898ea84 100644
--- a/lib/backends/fanotify.c
+++ b/lib/backends/fanotify.c
@@ -169,7 +169,8 @@ static int erofs_fanotify_handle_range(struct erofs_fanotify_ctx *ctx,
 		  (unsigned long long)(offset + length));
 
 	read_len = erofs_io_pread(&ctx->vd, ctx->fetch_buf, length, offset);
-	if (read_len < 0) {
+	if (read_len != length) {
+		read_len = read_len < 0 ? read_len : -EIO;
 		erofs_err("Failed to fetch range [%llu, %llu): %s",
 			  (unsigned long long)offset,
 			  (unsigned long long)(offset + length),
diff --git a/lib/backends/nbd.c b/lib/backends/nbd.c
index db0df44..81506b1 100644
--- a/lib/backends/nbd.c
+++ b/lib/backends/nbd.c
@@ -600,6 +600,8 @@ int erofs_nbd_get_request(int skfd, struct erofs_nbd_request *rq)
 	int err;
 
 	err = erofs_io_read(&vf, rq, sizeof(*rq));
+	if (err < 0)
+		return err;
 	if (err < sizeof(*rq))
 		return -EPIPE;
 
diff --git a/lib/backends/ublk.c b/lib/backends/ublk.c
index d2c5e19..7fa88d9 100644
--- a/lib/backends/ublk.c
+++ b/lib/backends/ublk.c
@@ -630,7 +630,7 @@ static int ublk_handle_io(struct erofs_ublk_queue *q, int tag)
 		if (ret < 0)
 			io->result = ret;
 		else
-			io->result = req.nr_sectors << 9;
+			io->result = req.result;
 	} else {
 		io->result = -EOPNOTSUPP;
 	}
diff --git a/lib/compress.c b/lib/compress.c
index b5f75ca..e764e44 100644
--- a/lib/compress.c
+++ b/lib/compress.c
@@ -1386,7 +1386,7 @@ int z_erofs_compress_segment(struct z_erofs_compress_sctx *ctx,
 			erofs_io_pread(vf, ctx->queue + ctx->tail, rx,
 				       ictx->fpos + offset));
 		if (ret != rx)
-			return -errno;
+			return ret < 0 ? ret : -EIO;
 
 		ctx->remaining -= rx;
 		ctx->tail += rx;
diff --git a/lib/fragments.c b/lib/fragments.c
index 3398888..2313daf 100644
--- a/lib/fragments.c
+++ b/lib/fragments.c
@@ -148,7 +148,7 @@ int erofs_fragment_findmatch(struct erofs_inode *inode,
 	ret = erofs_io_pread(vf, data, s1, fpos + inode->i_size - s1);
 	if (ret != s1) {
 		free(data);
-		return -errno;
+		return ret < 0 ? ret : -EIO;
 	}
 	e1 = s1 - EROFS_TOF_HASHLEN;
 	deduped = 0;
diff --git a/lib/inode.c b/lib/inode.c
index f687857..c9f8dd6 100644
--- a/lib/inode.c
+++ b/lib/inode.c
@@ -2024,18 +2024,17 @@ static int erofs_set_inode_fingerprint(struct erofs_inode *inode, int fd,
 	if (!ishare_xattr_prefix_id)
 		return 0;
 	erofs_sha256_init(&md);
-	do {
+	while (remaining) {
 		u8 buf[32768];
 
 		ret = erofs_io_pread(&vf, buf,
 				     min_t(u64, remaining, sizeof(buf)), pos);
-		if (ret < 0)
-			return ret;
-		if (ret > 0)
-			erofs_sha256_process(&md, buf, ret);
+		if (ret <= 0)
+			return ret < 0 ? ret : -EIO;
+		erofs_sha256_process(&md, buf, ret);
 		remaining -= ret;
 		pos += ret;
-	} while (remaining);
+	}
 	erofs_sha256_done(&md, out + sizeof("sha256:") - 1);
 #if defined(_WIN32) && !defined(__CYGWIN__)
 	ret = erofs_io_lseek(&vf, pos - inode->i_size, SEEK_SET);
diff --git a/lib/remotes/oci.c b/lib/remotes/oci.c
index 948d699..3e86e91 100644
--- a/lib/remotes/oci.c
+++ b/lib/remotes/oci.c
@@ -1491,6 +1491,7 @@ static ssize_t ocierofs_io_pread(struct erofs_vfile *vf, void *buf, size_t len,
 		return ret;
 
 	if (download_buf && download_size > 0) {
+		download_size = min_t(size_t, download_size, len);
 		memcpy(buf, download_buf, download_size);
 		free(download_buf);
 		return download_size;
diff --git a/lib/super.c b/lib/super.c
index 694a3e9..c6a9230 100644
--- a/lib/super.c
+++ b/lib/super.c
@@ -89,7 +89,7 @@ int erofs_read_superblock(struct erofs_sb_info *sbi)
 		return 0;
 
 	read = erofs_io_pread(&sbi->bdev, data, EROFS_MAX_BLOCK_SIZE, 0);
-	if (read < EROFS_SUPER_OFFSET + sizeof(*dsb)) {
+	if (read < 0 || read < EROFS_SUPER_OFFSET + sizeof(*dsb)) {
 		ret = read < 0 ? read : -EIO;
 		erofs_err("cannot read erofs superblock: %s",
 			  erofs_strerror(ret));
diff --git a/mount/main.c b/mount/main.c
index 347a71b..345053b 100644
--- a/mount/main.c
+++ b/mount/main.c
@@ -591,8 +591,8 @@ static ssize_t erofsmount_tarindex_pread(struct erofs_vfile *vf, void *buf,
 	if (index_part) {
 		local_read = erofs_io_pread(&tp->tarindex_vf, buf,
 					    index_part, offset);
-		if (local_read < 0)
-			return local_read;
+		if (local_read != index_part)
+			return local_read < 0 ? local_read : -EIO;
 	}
 	if (tardata_part) {
 		remote_read = erofs_io_pread(tp->zinfo_vf, buf + local_read,
@@ -1460,9 +1460,9 @@ static int erofsmount_ublk_handler(void *ctx, struct erofs_ublk_request *rq)
 
 	ret = erofs_io_pread(vf, rq->buf, rq->nr_sectors << 9,
 			     rq->start_sector << 9);
-	if (ret < 0) {
-		rq->result = -EIO;
-		return (int)ret;
+	if (ret != (rq->nr_sectors << 9)) {
+		rq->result = ret < 0 ? ret : -EIO;
+		return rq->result;
 	}
 	rq->result = ret;
 	return 0;
-- 
2.56.0



^ permalink raw reply related	[flat|nested] 11+ messages in thread

* Re: [PATCH 4/8] erofs-utils: lib: fix buffer leaks in error paths
  2026-11-12 12:47 ` [PATCH 4/8] erofs-utils: lib: fix buffer leaks in error paths Yifan Zhao
@ 2026-11-12 23:20   ` Gao Xiang
  0 siblings, 0 replies; 11+ messages in thread
From: Gao Xiang @ 2026-11-12 23:20 UTC (permalink / raw)
  To: Yifan Zhao; +Cc: linux-erofs

Hi Yifan,

On Thu, Nov 12, 2026 at 08:47:21PM +0800, Yifan Zhao wrote:
> Fragment data is already written before its buffer is shrunk.
> A failed realloc() should leave the original buffer valid, so the
> fragment commit can continue without shrinking it.
> 
> Also fix an inline data buffer leak when loading compressed metadata
> fails during rebuild.
> 
> Fixes: 84bae6acdbee ("erofs-utils: lib: keep full data until the fragment is committed")
> Fixes: 1c230a485f25 ("erofs-utils: mkfs: support rebuild mode for compressed inodes")
> Assisted-by: Codex:gpt-6-astra
> Assisted-by: Claude Code:deepseek-v4.1-flash-1017
> Signed-off-by: Yifan Zhao <stopire@gmail.com>
> ---
>  lib/compress.c  | 2 ++
>  lib/fragments.c | 8 ++------
>  2 files changed, 4 insertions(+), 6 deletions(-)
> 
> diff --git a/lib/compress.c b/lib/compress.c
> index e1cfc05..b5f75ca 100644
> --- a/lib/compress.c
> +++ b/lib/compress.c
> @@ -2607,6 +2607,8 @@ int z_erofs_rebuild_load_metadata(struct erofs_sb_info *dst_sbi,
>  err_free_ei:
>  	free(ei);
>  err_out:
> +	free(inode->idata);
> +	inode->idata = NULL;
>  	list_for_each_entry_safe(ei, n, &extents, list) {
>  		list_del(&ei->list);
>  		free(ei);

Can we use a separate patch to fix that?

> diff --git a/lib/fragments.c b/lib/fragments.c
> index d4e79b2..3398888 100644
> --- a/lib/fragments.c
> +++ b/lib/fragments.c
> @@ -366,12 +366,8 @@ int erofs_fragment_commit(struct erofs_inode *inode, u32 tofh)
>  		memmove(fi->data, fi->data + fi->length - sz, sz);
>  
>  		nb = realloc(fi->data, sz);
> -		if (!nb) {
> -			erofs_up_write(&bk->lock);
> -			fi->data = NULL;
> -			return -ENOMEM;
> -		}
> -		fi->data = nb;
> +		if (nb)
> +			fi->data = nb;

Does this one impact the reproducibility?

I mean that if realloc fails, we should just error out instead of
falling back, otherwise the generated image can be different.


Thanks,
Gao Xiang
>  		fi->pos = (erofs_off_t)offset;
>  		erofs_up_write(&bk->lock);
>  		inode->fragmentoff = fi->pos - len;
> -- 
> 2.56.0
> 
> 


^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH 8/8] erofs-utils: fix read error and short read handling
  2026-11-12 12:47 ` [PATCH 8/8] erofs-utils: fix read error and short read handling Yifan Zhao
@ 2026-11-12 23:41   ` Gao Xiang
  0 siblings, 0 replies; 11+ messages in thread
From: Gao Xiang @ 2026-11-12 23:41 UTC (permalink / raw)
  To: Yifan Zhao; +Cc: linux-erofs

On Thu, Nov 12, 2026 at 08:47:25PM +0800, Yifan Zhao wrote:
> Several erofs_io_read() and erofs_io_pread() callers mishandle negative
> errors or unexpected short reads, potentially reporting success or
> looping at EOF.
> 
> Propagate negative errors, reject unexpected short reads and premature
> EOF, and preserve the result reported by the ublk handler.
> 
> Also cap OCI blob copies at the requested length.
> 
> Assisted-by: Codex:gpt-6-astra
> Assisted-by: Claude Code:deepseek-v4.1-flash-1017
> Signed-off-by: Yifan Zhao <stopire@gmail.com>
> ---
>  lib/backends/fanotify.c |  3 ++-
>  lib/backends/nbd.c      |  2 ++
>  lib/backends/ublk.c     |  2 +-
>  lib/compress.c          |  2 +-
>  lib/fragments.c         |  2 +-
>  lib/inode.c             | 11 +++++------
>  lib/remotes/oci.c       |  1 +
>  lib/super.c             |  2 +-
>  mount/main.c            | 10 +++++-----
>  9 files changed, 19 insertions(+), 16 deletions(-)
> 
> diff --git a/lib/backends/fanotify.c b/lib/backends/fanotify.c
> index cf8b616..898ea84 100644
> --- a/lib/backends/fanotify.c
> +++ b/lib/backends/fanotify.c
> @@ -169,7 +169,8 @@ static int erofs_fanotify_handle_range(struct erofs_fanotify_ctx *ctx,
>  		  (unsigned long long)(offset + length));
>  
>  	read_len = erofs_io_pread(&ctx->vd, ctx->fetch_buf, length, offset);
> -	if (read_len < 0) {
> +	if (read_len != length) {
> +		read_len = read_len < 0 ? read_len : -EIO;
>  		erofs_err("Failed to fetch range [%llu, %llu): %s",
>  			  (unsigned long long)offset,
>  			  (unsigned long long)(offset + length),
> diff --git a/lib/backends/nbd.c b/lib/backends/nbd.c
> index db0df44..81506b1 100644
> --- a/lib/backends/nbd.c
> +++ b/lib/backends/nbd.c
> @@ -600,6 +600,8 @@ int erofs_nbd_get_request(int skfd, struct erofs_nbd_request *rq)
>  	int err;
>  
>  	err = erofs_io_read(&vf, rq, sizeof(*rq));
> +	if (err < 0)
> +		return err;
>  	if (err < sizeof(*rq))
>  		return -EPIPE;
>  
> diff --git a/lib/backends/ublk.c b/lib/backends/ublk.c
> index d2c5e19..7fa88d9 100644
> --- a/lib/backends/ublk.c
> +++ b/lib/backends/ublk.c
> @@ -630,7 +630,7 @@ static int ublk_handle_io(struct erofs_ublk_queue *q, int tag)
>  		if (ret < 0)
>  			io->result = ret;
>  		else
> -			io->result = req.nr_sectors << 9;
> +			io->result = req.result;

I don't apply this one, because I think there are two many changes
related to different interfaces.

especially this one, I don't know what happens just according to
the code here.

Could you just split this into multiple patch, each patch address one
interface, like erofs_io_pread()... etc.

I applied the remaining ones, so next time just resend these two.

Thanks,
Gao Xiang


^ permalink raw reply	[flat|nested] 11+ messages in thread

end of thread, other threads:[~2026-11-12 23:41 UTC | newest]

Thread overview: 11+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-11-12 12:47 [PATCH 0/8] erofs-utils: fix issues found by LLMs Yifan Zhao
2026-11-12 12:47 ` [PATCH 1/8] erofs-utils: lib: fix arithmetic overflow in large file handling Yifan Zhao
2026-11-12 12:47 ` [PATCH 2/8] erofs-utils: mkfs: fix incremental superblock stack overread Yifan Zhao
2026-11-12 12:47 ` [PATCH 3/8] erofs-utils: tar: fix out-of-bounds access when trimming PAX paths Yifan Zhao
2026-11-12 12:47 ` [PATCH 4/8] erofs-utils: lib: fix buffer leaks in error paths Yifan Zhao
2026-11-12 23:20   ` Gao Xiang
2026-11-12 12:47 ` [PATCH 5/8] erofs-utils: exclude: fix stack overflow when checking long paths Yifan Zhao
2026-11-12 12:47 ` [PATCH 6/8] erofs-utils: lib: fix gzran EOF handling and state leaks Yifan Zhao
2026-11-12 12:47 ` [PATCH 7/8] erofs-utils: lib: fix metabox inline data reads Yifan Zhao
2026-11-12 12:47 ` [PATCH 8/8] erofs-utils: fix read error and short read handling Yifan Zhao
2026-11-12 23:41   ` Gao Xiang

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox