You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
118 lines
3.2 KiB
118 lines
3.2 KiB
https://git.kernel.org/xiang/erofs-utils/c/2145dff03dd3f3f74bcda3b52160fbad37f7fcfe
|
|
From: Gao Xiang <hsiangkao@linux.alibaba.com>
|
|
Date: Fri, 2 Jun 2023 11:05:19 +0800
|
|
Subject: erofs-utils: fsck: don't allocate/read too large extents
|
|
|
|
Since some crafted EROFS filesystem images could have insane large
|
|
extents, which causes unexpected bahaviors when extracting data.
|
|
|
|
Fix it by extracting large extents with a buffer of a reasonable
|
|
maximum size limit and reading multiple times instead.
|
|
|
|
Note that only `--extract` option is impacted.
|
|
|
|
CVE: CVE-2023-33552
|
|
Closes: https://nvd.nist.gov/vuln/detail/CVE-2023-33552
|
|
Reported-by: Chaoming Yang <lometsj@live.com>
|
|
Fixes: 412c8f908132 ("erofs-utils: fsck: add --extract=X support to extract to path X")
|
|
Signed-off-by: Gao Xiang <hsiangkao@linux.alibaba.com>
|
|
Link: https://lore.kernel.org/r/20230602030519.117071-1-hsiangkao@linux.alibaba.com
|
|
--- a/fsck/main.c
|
|
+++ b/fsck/main.c
|
|
@@ -392,6 +392,8 @@ static int erofs_verify_inode_data(struct erofs_inode *inode, int outfd)
|
|
}
|
|
|
|
while (pos < inode->i_size) {
|
|
+ unsigned int alloc_rawsize;
|
|
+
|
|
map.m_la = pos;
|
|
if (compressed)
|
|
ret = z_erofs_map_blocks_iter(inode, &map,
|
|
@@ -420,10 +422,28 @@ static int erofs_verify_inode_data(struct erofs_inode *inode, int outfd)
|
|
if (!(map.m_flags & EROFS_MAP_MAPPED) || !fsckcfg.check_decomp)
|
|
continue;
|
|
|
|
- if (map.m_plen > raw_size) {
|
|
- raw_size = map.m_plen;
|
|
- raw = realloc(raw, raw_size);
|
|
- BUG_ON(!raw);
|
|
+ if (map.m_plen > Z_EROFS_PCLUSTER_MAX_SIZE) {
|
|
+ if (compressed) {
|
|
+ erofs_err("invalid pcluster size %" PRIu64 " @ offset %" PRIu64 " of nid %" PRIu64,
|
|
+ map.m_plen, map.m_la,
|
|
+ inode->nid | 0ULL);
|
|
+ ret = -EFSCORRUPTED;
|
|
+ goto out;
|
|
+ }
|
|
+ alloc_rawsize = Z_EROFS_PCLUSTER_MAX_SIZE;
|
|
+ } else {
|
|
+ alloc_rawsize = map.m_plen;
|
|
+ }
|
|
+
|
|
+ if (alloc_rawsize > raw_size) {
|
|
+ char *newraw = realloc(raw, alloc_rawsize);
|
|
+
|
|
+ if (!newraw) {
|
|
+ ret = -ENOMEM;
|
|
+ goto out;
|
|
+ }
|
|
+ raw = newraw;
|
|
+ raw_size = alloc_rawsize;
|
|
}
|
|
|
|
if (compressed) {
|
|
@@ -434,18 +454,27 @@ static int erofs_verify_inode_data(struct erofs_inode *inode, int outfd)
|
|
}
|
|
ret = z_erofs_read_one_data(inode, &map, raw, buffer,
|
|
0, map.m_llen, false);
|
|
+ if (ret)
|
|
+ goto out;
|
|
+
|
|
+ if (outfd >= 0 && write(outfd, buffer, map.m_llen) < 0)
|
|
+ goto fail_eio;
|
|
} else {
|
|
- ret = erofs_read_one_data(&map, raw, 0, map.m_plen);
|
|
- }
|
|
- if (ret)
|
|
- goto out;
|
|
+ u64 p = 0;
|
|
|
|
- if (outfd >= 0 && write(outfd, compressed ? buffer : raw,
|
|
- map.m_llen) < 0) {
|
|
- erofs_err("I/O error occurred when verifying data chunk @ nid %llu",
|
|
- inode->nid | 0ULL);
|
|
- ret = -EIO;
|
|
- goto out;
|
|
+ do {
|
|
+ u64 count = min_t(u64, alloc_rawsize,
|
|
+ map.m_llen);
|
|
+
|
|
+ ret = erofs_read_one_data(&map, raw, p, count);
|
|
+ if (ret)
|
|
+ goto out;
|
|
+
|
|
+ if (outfd >= 0 && write(outfd, raw, count) < 0)
|
|
+ goto fail_eio;
|
|
+ map.m_llen -= count;
|
|
+ p += count;
|
|
+ } while (map.m_llen);
|
|
}
|
|
}
|
|
|
|
@@ -460,6 +489,12 @@ out:
|
|
if (buffer)
|
|
free(buffer);
|
|
return ret < 0 ? ret : 0;
|
|
+
|
|
+fail_eio:
|
|
+ erofs_err("I/O error occurred when verifying data chunk @ nid %llu",
|
|
+ inode->nid | 0ULL);
|
|
+ ret = -EIO;
|
|
+ goto out;
|
|
}
|
|
|
|
static inline int erofs_extract_dir(struct erofs_inode *inode)
|
|
--
|
|
cgit
|
|
|