diff options
5 files changed, 529 insertions, 0 deletions
diff --git a/meta/recipes-devtools/erofs-utils/erofs-utils/CVE-2023-33551.patch b/meta/recipes-devtools/erofs-utils/erofs-utils/CVE-2023-33551.patch new file mode 100644 index 0000000000..9ed77d921f --- /dev/null +++ b/meta/recipes-devtools/erofs-utils/erofs-utils/CVE-2023-33551.patch | |||
| @@ -0,0 +1,80 @@ | |||
| 1 | From 5782f0d47df99dcfc743aa138361336e9a4ac966 Mon Sep 17 00:00:00 2001 | ||
| 2 | From: Gao Xiang <hsiangkao@linux.alibaba.com> | ||
| 3 | Date: Fri, 2 Jun 2023 13:52:56 +0800 | ||
| 4 | Subject: [PATCH 1/4] erofs-utils: fsck: block insane long paths when | ||
| 5 | extracting images | ||
| 6 | |||
| 7 | Since some crafted EROFS filesystem images could have insane deep | ||
| 8 | hierarchy (or may form directory loops) which triggers the | ||
| 9 | PATH_MAX-sized path buffer OR stack overflow. | ||
| 10 | |||
| 11 | Actually some crafted images cannot be deemed as real corrupted | ||
| 12 | images but over-PATH_MAX paths are not something that we'd like to | ||
| 13 | support for now. | ||
| 14 | |||
| 15 | CVE: CVE-2023-33551 | ||
| 16 | Closes: https://nvd.nist.gov/vuln/detail/CVE-2023-33551 | ||
| 17 | Reported-by: Chaoming Yang <lometsj@live.com> | ||
| 18 | Fixes: f44043561491 ("erofs-utils: introduce fsck.erofs") | ||
| 19 | Fixes: b11f84f593f9 ("erofs-utils: fsck: convert to use erofs_iterate_dir()") | ||
| 20 | Fixes: 412c8f908132 ("erofs-utils: fsck: add --extract=X support to extract to path X") | ||
| 21 | Signeo-off-by: Gao Xiang <hsiangkao@linux.alibaba.com> | ||
| 22 | Link: https://lore.kernel.org/r/20230602055256.18061-1-hsiangkao@linux.alibaba.com | ||
| 23 | |||
| 24 | Upstream-Status: Backport [https://git.kernel.org/pub/scm/linux/kernel/git/xiang/erofs-utils.git/patch/?id=27aeef179bf17d5f1d98f827e93d24839a6d4176] | ||
| 25 | Signed-off-by: Changqing Li <changqing.li@windriver.com> | ||
| 26 | --- | ||
| 27 | fsck/main.c | 23 +++++++++++++++-------- | ||
| 28 | 1 file changed, 15 insertions(+), 8 deletions(-) | ||
| 29 | |||
| 30 | diff --git a/fsck/main.c b/fsck/main.c | ||
| 31 | index 5a2f659..2b6a6dd 100644 | ||
| 32 | --- a/fsck/main.c | ||
| 33 | +++ b/fsck/main.c | ||
| 34 | @@ -679,28 +679,35 @@ again: | ||
| 35 | static int erofsfsck_dirent_iter(struct erofs_dir_context *ctx) | ||
| 36 | { | ||
| 37 | int ret; | ||
| 38 | - size_t prev_pos = fsckcfg.extract_pos; | ||
| 39 | + size_t prev_pos, curr_pos; | ||
| 40 | |||
| 41 | if (ctx->dot_dotdot) | ||
| 42 | return 0; | ||
| 43 | |||
| 44 | - if (fsckcfg.extract_path) { | ||
| 45 | - size_t curr_pos = prev_pos; | ||
| 46 | + prev_pos = fsckcfg.extract_pos; | ||
| 47 | + curr_pos = prev_pos; | ||
| 48 | + | ||
| 49 | + if (prev_pos + ctx->de_namelen >= PATH_MAX) { | ||
| 50 | + erofs_err("unable to fsck since the path is too long (%u)", | ||
| 51 | + curr_pos + ctx->de_namelen); | ||
| 52 | + return -EOPNOTSUPP; | ||
| 53 | + } | ||
| 54 | |||
| 55 | + if (fsckcfg.extract_path) { | ||
| 56 | fsckcfg.extract_path[curr_pos++] = '/'; | ||
| 57 | strncpy(fsckcfg.extract_path + curr_pos, ctx->dname, | ||
| 58 | ctx->de_namelen); | ||
| 59 | curr_pos += ctx->de_namelen; | ||
| 60 | fsckcfg.extract_path[curr_pos] = '\0'; | ||
| 61 | - fsckcfg.extract_pos = curr_pos; | ||
| 62 | + } else { | ||
| 63 | + curr_pos += ctx->de_namelen; | ||
| 64 | } | ||
| 65 | - | ||
| 66 | + fsckcfg.extract_pos = curr_pos; | ||
| 67 | ret = erofsfsck_check_inode(ctx->dir->nid, ctx->de_nid); | ||
| 68 | |||
| 69 | - if (fsckcfg.extract_path) { | ||
| 70 | + if (fsckcfg.extract_path) | ||
| 71 | fsckcfg.extract_path[prev_pos] = '\0'; | ||
| 72 | - fsckcfg.extract_pos = prev_pos; | ||
| 73 | - } | ||
| 74 | + fsckcfg.extract_pos = prev_pos; | ||
| 75 | return ret; | ||
| 76 | } | ||
| 77 | |||
| 78 | -- | ||
| 79 | 2.25.1 | ||
| 80 | |||
diff --git a/meta/recipes-devtools/erofs-utils/erofs-utils/CVE-2023-33552-1.patch b/meta/recipes-devtools/erofs-utils/erofs-utils/CVE-2023-33552-1.patch new file mode 100644 index 0000000000..011ca1cd5e --- /dev/null +++ b/meta/recipes-devtools/erofs-utils/erofs-utils/CVE-2023-33552-1.patch | |||
| @@ -0,0 +1,221 @@ | |||
| 1 | From 8aef6015a03242a7d13467d23ad52b5427bf5247 Mon Sep 17 00:00:00 2001 | ||
| 2 | From: Yue Hu <huyue2@coolpad.com> | ||
| 3 | Date: Wed, 11 Jan 2023 09:49:26 +0800 | ||
| 4 | Subject: [PATCH] erofs-utils: lib: export parts of erofs_pread() | ||
| 5 | |||
| 6 | Export parts of erofs_pread() to avoid duplicated code in | ||
| 7 | erofs_verify_inode_data(). Let's make two helpers for this. | ||
| 8 | |||
| 9 | Signed-off-by: Yue Hu <huyue2@coolpad.com> | ||
| 10 | Link: https://lore.kernel.org/r/ff560da9c798b2ca1f1a663a000501486d865487.1673401718.git.huyue2@coolpad.com | ||
| 11 | Signed-off-by: Gao Xiang <hsiangkao@linux.alibaba.com> | ||
| 12 | |||
| 13 | CVE: CVE-2023-33552 | ||
| 14 | Upstream-Status: Backport [https://git.kernel.org/pub/scm/linux/kernel/git/xiang/erofs-utils.git/commit/?id=4c0fb15a5d85378debe9d10d96cd643d167300ca] | ||
| 15 | Signed-off-by: Changqing Li <changqing.li@windriver.com> | ||
| 16 | --- | ||
| 17 | include/erofs/internal.h | 5 ++ | ||
| 18 | lib/data.c | 108 ++++++++++++++++++++++++--------------- | ||
| 19 | 2 files changed, 71 insertions(+), 42 deletions(-) | ||
| 20 | |||
| 21 | diff --git a/include/erofs/internal.h b/include/erofs/internal.h | ||
| 22 | index d3b2986..28d0e68 100644 | ||
| 23 | --- a/include/erofs/internal.h | ||
| 24 | +++ b/include/erofs/internal.h | ||
| 25 | @@ -335,6 +335,11 @@ int erofs_pread(struct erofs_inode *inode, char *buf, | ||
| 26 | int erofs_map_blocks(struct erofs_inode *inode, | ||
| 27 | struct erofs_map_blocks *map, int flags); | ||
| 28 | int erofs_map_dev(struct erofs_sb_info *sbi, struct erofs_map_dev *map); | ||
| 29 | +int erofs_read_one_data(struct erofs_map_blocks *map, char *buffer, u64 offset, | ||
| 30 | + size_t len); | ||
| 31 | +int z_erofs_read_one_data(struct erofs_inode *inode, | ||
| 32 | + struct erofs_map_blocks *map, char *raw, char *buffer, | ||
| 33 | + erofs_off_t skip, erofs_off_t length, bool trimmed); | ||
| 34 | |||
| 35 | static inline int erofs_get_occupied_size(const struct erofs_inode *inode, | ||
| 36 | erofs_off_t *size) | ||
| 37 | diff --git a/lib/data.c b/lib/data.c | ||
| 38 | index 6bc554d..2a7fdd5 100644 | ||
| 39 | --- a/lib/data.c | ||
| 40 | +++ b/lib/data.c | ||
| 41 | @@ -158,19 +158,38 @@ int erofs_map_dev(struct erofs_sb_info *sbi, struct erofs_map_dev *map) | ||
| 42 | return 0; | ||
| 43 | } | ||
| 44 | |||
| 45 | +int erofs_read_one_data(struct erofs_map_blocks *map, char *buffer, u64 offset, | ||
| 46 | + size_t len) | ||
| 47 | +{ | ||
| 48 | + struct erofs_map_dev mdev; | ||
| 49 | + int ret; | ||
| 50 | + | ||
| 51 | + mdev = (struct erofs_map_dev) { | ||
| 52 | + .m_deviceid = map->m_deviceid, | ||
| 53 | + .m_pa = map->m_pa, | ||
| 54 | + }; | ||
| 55 | + ret = erofs_map_dev(&sbi, &mdev); | ||
| 56 | + if (ret) | ||
| 57 | + return ret; | ||
| 58 | + | ||
| 59 | + ret = dev_read(mdev.m_deviceid, buffer, mdev.m_pa + offset, len); | ||
| 60 | + if (ret < 0) | ||
| 61 | + return -EIO; | ||
| 62 | + return 0; | ||
| 63 | +} | ||
| 64 | + | ||
| 65 | static int erofs_read_raw_data(struct erofs_inode *inode, char *buffer, | ||
| 66 | erofs_off_t size, erofs_off_t offset) | ||
| 67 | { | ||
| 68 | struct erofs_map_blocks map = { | ||
| 69 | .index = UINT_MAX, | ||
| 70 | }; | ||
| 71 | - struct erofs_map_dev mdev; | ||
| 72 | int ret; | ||
| 73 | erofs_off_t ptr = offset; | ||
| 74 | |||
| 75 | while (ptr < offset + size) { | ||
| 76 | char *const estart = buffer + ptr - offset; | ||
| 77 | - erofs_off_t eend; | ||
| 78 | + erofs_off_t eend, moff = 0; | ||
| 79 | |||
| 80 | map.m_la = ptr; | ||
| 81 | ret = erofs_map_blocks(inode, &map, 0); | ||
| 82 | @@ -179,14 +198,6 @@ static int erofs_read_raw_data(struct erofs_inode *inode, char *buffer, | ||
| 83 | |||
| 84 | DBG_BUGON(map.m_plen != map.m_llen); | ||
| 85 | |||
| 86 | - mdev = (struct erofs_map_dev) { | ||
| 87 | - .m_deviceid = map.m_deviceid, | ||
| 88 | - .m_pa = map.m_pa, | ||
| 89 | - }; | ||
| 90 | - ret = erofs_map_dev(&sbi, &mdev); | ||
| 91 | - if (ret) | ||
| 92 | - return ret; | ||
| 93 | - | ||
| 94 | /* trim extent */ | ||
| 95 | eend = min(offset + size, map.m_la + map.m_llen); | ||
| 96 | DBG_BUGON(ptr < map.m_la); | ||
| 97 | @@ -204,19 +215,54 @@ static int erofs_read_raw_data(struct erofs_inode *inode, char *buffer, | ||
| 98 | } | ||
| 99 | |||
| 100 | if (ptr > map.m_la) { | ||
| 101 | - mdev.m_pa += ptr - map.m_la; | ||
| 102 | + moff = ptr - map.m_la; | ||
| 103 | map.m_la = ptr; | ||
| 104 | } | ||
| 105 | |||
| 106 | - ret = dev_read(mdev.m_deviceid, estart, mdev.m_pa, | ||
| 107 | - eend - map.m_la); | ||
| 108 | - if (ret < 0) | ||
| 109 | - return -EIO; | ||
| 110 | + ret = erofs_read_one_data(&map, estart, moff, eend - map.m_la); | ||
| 111 | + if (ret) | ||
| 112 | + return ret; | ||
| 113 | ptr = eend; | ||
| 114 | } | ||
| 115 | return 0; | ||
| 116 | } | ||
| 117 | |||
| 118 | +int z_erofs_read_one_data(struct erofs_inode *inode, | ||
| 119 | + struct erofs_map_blocks *map, char *raw, char *buffer, | ||
| 120 | + erofs_off_t skip, erofs_off_t length, bool trimmed) | ||
| 121 | +{ | ||
| 122 | + struct erofs_map_dev mdev; | ||
| 123 | + int ret = 0; | ||
| 124 | + | ||
| 125 | + /* no device id here, thus it will always succeed */ | ||
| 126 | + mdev = (struct erofs_map_dev) { | ||
| 127 | + .m_pa = map->m_pa, | ||
| 128 | + }; | ||
| 129 | + ret = erofs_map_dev(&sbi, &mdev); | ||
| 130 | + if (ret) { | ||
| 131 | + DBG_BUGON(1); | ||
| 132 | + return ret; | ||
| 133 | + } | ||
| 134 | + | ||
| 135 | + ret = dev_read(mdev.m_deviceid, raw, mdev.m_pa, map->m_plen); | ||
| 136 | + if (ret < 0) | ||
| 137 | + return ret; | ||
| 138 | + | ||
| 139 | + ret = z_erofs_decompress(&(struct z_erofs_decompress_req) { | ||
| 140 | + .in = raw, | ||
| 141 | + .out = buffer, | ||
| 142 | + .decodedskip = skip, | ||
| 143 | + .inputsize = map->m_plen, | ||
| 144 | + .decodedlength = length, | ||
| 145 | + .alg = map->m_algorithmformat, | ||
| 146 | + .partial_decoding = trimmed ? true : | ||
| 147 | + !(map->m_flags & EROFS_MAP_FULL_MAPPED) | ||
| 148 | + }); | ||
| 149 | + if (ret < 0) | ||
| 150 | + return ret; | ||
| 151 | + return 0; | ||
| 152 | +} | ||
| 153 | + | ||
| 154 | static int z_erofs_read_data(struct erofs_inode *inode, char *buffer, | ||
| 155 | erofs_off_t size, erofs_off_t offset) | ||
| 156 | { | ||
| 157 | @@ -224,8 +270,7 @@ static int z_erofs_read_data(struct erofs_inode *inode, char *buffer, | ||
| 158 | struct erofs_map_blocks map = { | ||
| 159 | .index = UINT_MAX, | ||
| 160 | }; | ||
| 161 | - struct erofs_map_dev mdev; | ||
| 162 | - bool partial; | ||
| 163 | + bool trimmed; | ||
| 164 | unsigned int bufsize = 0; | ||
| 165 | char *raw = NULL; | ||
| 166 | int ret = 0; | ||
| 167 | @@ -238,27 +283,17 @@ static int z_erofs_read_data(struct erofs_inode *inode, char *buffer, | ||
| 168 | if (ret) | ||
| 169 | break; | ||
| 170 | |||
| 171 | - /* no device id here, thus it will always succeed */ | ||
| 172 | - mdev = (struct erofs_map_dev) { | ||
| 173 | - .m_pa = map.m_pa, | ||
| 174 | - }; | ||
| 175 | - ret = erofs_map_dev(&sbi, &mdev); | ||
| 176 | - if (ret) { | ||
| 177 | - DBG_BUGON(1); | ||
| 178 | - break; | ||
| 179 | - } | ||
| 180 | - | ||
| 181 | /* | ||
| 182 | * trim to the needed size if the returned extent is quite | ||
| 183 | * larger than requested, and set up partial flag as well. | ||
| 184 | */ | ||
| 185 | if (end < map.m_la + map.m_llen) { | ||
| 186 | length = end - map.m_la; | ||
| 187 | - partial = true; | ||
| 188 | + trimmed = true; | ||
| 189 | } else { | ||
| 190 | DBG_BUGON(end != map.m_la + map.m_llen); | ||
| 191 | length = map.m_llen; | ||
| 192 | - partial = !(map.m_flags & EROFS_MAP_FULL_MAPPED); | ||
| 193 | + trimmed = false; | ||
| 194 | } | ||
| 195 | |||
| 196 | if (map.m_la < offset) { | ||
| 197 | @@ -283,19 +318,8 @@ static int z_erofs_read_data(struct erofs_inode *inode, char *buffer, | ||
| 198 | break; | ||
| 199 | } | ||
| 200 | } | ||
| 201 | - ret = dev_read(mdev.m_deviceid, raw, mdev.m_pa, map.m_plen); | ||
| 202 | - if (ret < 0) | ||
| 203 | - break; | ||
| 204 | - | ||
| 205 | - ret = z_erofs_decompress(&(struct z_erofs_decompress_req) { | ||
| 206 | - .in = raw, | ||
| 207 | - .out = buffer + end - offset, | ||
| 208 | - .decodedskip = skip, | ||
| 209 | - .inputsize = map.m_plen, | ||
| 210 | - .decodedlength = length, | ||
| 211 | - .alg = map.m_algorithmformat, | ||
| 212 | - .partial_decoding = partial | ||
| 213 | - }); | ||
| 214 | + ret = z_erofs_read_one_data(inode, &map, raw, | ||
| 215 | + buffer + end - offset, skip, length, trimmed); | ||
| 216 | if (ret < 0) | ||
| 217 | break; | ||
| 218 | } | ||
| 219 | -- | ||
| 220 | 2.25.1 | ||
| 221 | |||
diff --git a/meta/recipes-devtools/erofs-utils/erofs-utils/CVE-2023-33552-2.patch b/meta/recipes-devtools/erofs-utils/erofs-utils/CVE-2023-33552-2.patch new file mode 100644 index 0000000000..4d190363b9 --- /dev/null +++ b/meta/recipes-devtools/erofs-utils/erofs-utils/CVE-2023-33552-2.patch | |||
| @@ -0,0 +1,97 @@ | |||
| 1 | From 3a360e01058467573bd7239fa430d8dc5fbd60f4 Mon Sep 17 00:00:00 2001 | ||
| 2 | From: Yue Hu <huyue2@coolpad.com> | ||
| 3 | Date: Wed, 11 Jan 2023 09:49:27 +0800 | ||
| 4 | Subject: [PATCH 3/4] erofs-utils: fsck: cleanup erofs_verify_inode_data() | ||
| 5 | |||
| 6 | Diretly call {z_}erofs_read_one_data() to avoid duplicated code. | ||
| 7 | Accordingly, fragment and partial-referenced plusters are also supported | ||
| 8 | after this change. | ||
| 9 | |||
| 10 | Signed-off-by: Yue Hu <huyue2@coolpad.com> | ||
| 11 | Link: https://lore.kernel.org/r/115e61fc9c2d34cab6d3dd78383ac57c94a491fc.1673401718.git.huyue2@coolpad.com | ||
| 12 | Signed-off-by: Gao Xiang <hsiangkao@linux.alibaba.com> | ||
| 13 | |||
| 14 | CVE: CVE-2023-33552 | ||
| 15 | Upstream-Status: Backport [https://git.kernel.org/pub/scm/linux/kernel/git/xiang/erofs-utils.git/commit/?id=87430c69e1d542928c4519e8fabfd6348a741999] | ||
| 16 | Signed-off-by: Changqing Li <changqing.li@windriver.com> | ||
| 17 | --- | ||
| 18 | fsck/main.c | 53 ++++++++++------------------------------------------- | ||
| 19 | 1 file changed, 10 insertions(+), 43 deletions(-) | ||
| 20 | |||
| 21 | diff --git a/fsck/main.c b/fsck/main.c | ||
| 22 | index 2b6a6dd..92ef17a 100644 | ||
| 23 | --- a/fsck/main.c | ||
| 24 | +++ b/fsck/main.c | ||
| 25 | @@ -366,7 +366,6 @@ static int erofs_verify_inode_data(struct erofs_inode *inode, int outfd) | ||
| 26 | struct erofs_map_blocks map = { | ||
| 27 | .index = UINT_MAX, | ||
| 28 | }; | ||
| 29 | - struct erofs_map_dev mdev; | ||
| 30 | int ret = 0; | ||
| 31 | bool compressed; | ||
| 32 | erofs_off_t pos = 0; | ||
| 33 | @@ -427,51 +426,19 @@ static int erofs_verify_inode_data(struct erofs_inode *inode, int outfd) | ||
| 34 | BUG_ON(!raw); | ||
| 35 | } | ||
| 36 | |||
| 37 | - mdev = (struct erofs_map_dev) { | ||
| 38 | - .m_deviceid = map.m_deviceid, | ||
| 39 | - .m_pa = map.m_pa, | ||
| 40 | - }; | ||
| 41 | - ret = erofs_map_dev(&sbi, &mdev); | ||
| 42 | - if (ret) { | ||
| 43 | - erofs_err("failed to map device of m_pa %" PRIu64 ", m_deviceid %u @ nid %llu: %d", | ||
| 44 | - map.m_pa, map.m_deviceid, inode->nid | 0ULL, | ||
| 45 | - ret); | ||
| 46 | - goto out; | ||
| 47 | - } | ||
| 48 | - | ||
| 49 | - if (compressed && map.m_llen > buffer_size) { | ||
| 50 | - buffer_size = map.m_llen; | ||
| 51 | - buffer = realloc(buffer, buffer_size); | ||
| 52 | - BUG_ON(!buffer); | ||
| 53 | - } | ||
| 54 | - | ||
| 55 | - ret = dev_read(mdev.m_deviceid, raw, mdev.m_pa, map.m_plen); | ||
| 56 | - if (ret < 0) { | ||
| 57 | - erofs_err("failed to read data of m_pa %" PRIu64 ", m_plen %" PRIu64 " @ nid %llu: %d", | ||
| 58 | - mdev.m_pa, map.m_plen, inode->nid | 0ULL, | ||
| 59 | - ret); | ||
| 60 | - goto out; | ||
| 61 | - } | ||
| 62 | - | ||
| 63 | if (compressed) { | ||
| 64 | - struct z_erofs_decompress_req rq = { | ||
| 65 | - .in = raw, | ||
| 66 | - .out = buffer, | ||
| 67 | - .decodedskip = 0, | ||
| 68 | - .inputsize = map.m_plen, | ||
| 69 | - .decodedlength = map.m_llen, | ||
| 70 | - .alg = map.m_algorithmformat, | ||
| 71 | - .partial_decoding = 0 | ||
| 72 | - }; | ||
| 73 | - | ||
| 74 | - ret = z_erofs_decompress(&rq); | ||
| 75 | - if (ret < 0) { | ||
| 76 | - erofs_err("failed to decompress data of m_pa %" PRIu64 ", m_plen %" PRIu64 " @ nid %llu: %s", | ||
| 77 | - mdev.m_pa, map.m_plen, | ||
| 78 | - inode->nid | 0ULL, strerror(-ret)); | ||
| 79 | - goto out; | ||
| 80 | + if (map.m_llen > buffer_size) { | ||
| 81 | + buffer_size = map.m_llen; | ||
| 82 | + buffer = realloc(buffer, buffer_size); | ||
| 83 | + BUG_ON(!buffer); | ||
| 84 | } | ||
| 85 | + ret = z_erofs_read_one_data(inode, &map, raw, buffer, | ||
| 86 | + 0, map.m_llen, false); | ||
| 87 | + } else { | ||
| 88 | + ret = erofs_read_one_data(&map, raw, 0, map.m_plen); | ||
| 89 | } | ||
| 90 | + if (ret) | ||
| 91 | + goto out; | ||
| 92 | |||
| 93 | if (outfd >= 0 && write(outfd, compressed ? buffer : raw, | ||
| 94 | map.m_llen) < 0) { | ||
| 95 | -- | ||
| 96 | 2.25.1 | ||
| 97 | |||
diff --git a/meta/recipes-devtools/erofs-utils/erofs-utils/CVE-2023-33552-3.patch b/meta/recipes-devtools/erofs-utils/erofs-utils/CVE-2023-33552-3.patch new file mode 100644 index 0000000000..c05d62c5dd --- /dev/null +++ b/meta/recipes-devtools/erofs-utils/erofs-utils/CVE-2023-33552-3.patch | |||
| @@ -0,0 +1,127 @@ | |||
| 1 | From b4e155ba759ae389c5f71cd13d97eb3bcf2c1adf Mon Sep 17 00:00:00 2001 | ||
| 2 | From: Gao Xiang <hsiangkao@linux.alibaba.com> | ||
| 3 | Date: Fri, 2 Jun 2023 11:05:19 +0800 | ||
| 4 | Subject: [PATCH] erofs-utils: fsck: don't allocate/read too large extents | ||
| 5 | |||
| 6 | Since some crafted EROFS filesystem images could have insane large | ||
| 7 | extents, which causes unexpected bahaviors when extracting data. | ||
| 8 | |||
| 9 | Fix it by extracting large extents with a buffer of a reasonable | ||
| 10 | maximum size limit and reading multiple times instead. | ||
| 11 | |||
| 12 | Note that only `--extract` option is impacted. | ||
| 13 | |||
| 14 | CVE: CVE-2023-33552 | ||
| 15 | Closes: https://nvd.nist.gov/vuln/detail/CVE-2023-33552 | ||
| 16 | Reported-by: Chaoming Yang <lometsj@live.com> | ||
| 17 | Fixes: 412c8f908132 ("erofs-utils: fsck: add --extract=X support to extract to path X") | ||
| 18 | Signed-off-by: Gao Xiang <hsiangkao@linux.alibaba.com> | ||
| 19 | Link: https://lore.kernel.org/r/20230602030519.117071-1-hsiangkao@linux.alibaba.com | ||
| 20 | |||
| 21 | CVE: CVE-2023-33552 | ||
| 22 | Upstream-Status: Backport [https://git.kernel.org/pub/scm/linux/kernel/git/xiang/erofs-utils.git/patch/?id=2145dff03dd3f3f74bcda3b52160fbad37f7fcfe] | ||
| 23 | Signed-off-by: Changqing Li <changqing.li@windriver.com> | ||
| 24 | --- | ||
| 25 | fsck/main.c | 64 ++++++++++++++++++++++++++++++++++++++++------------- | ||
| 26 | 1 file changed, 49 insertions(+), 15 deletions(-) | ||
| 27 | |||
| 28 | diff --git a/fsck/main.c b/fsck/main.c | ||
| 29 | index 92ef17a..1bd1117 100644 | ||
| 30 | --- a/fsck/main.c | ||
| 31 | +++ b/fsck/main.c | ||
| 32 | @@ -392,6 +392,8 @@ static int erofs_verify_inode_data(struct erofs_inode *inode, int outfd) | ||
| 33 | } | ||
| 34 | |||
| 35 | while (pos < inode->i_size) { | ||
| 36 | + unsigned int alloc_rawsize; | ||
| 37 | + | ||
| 38 | map.m_la = pos; | ||
| 39 | if (compressed) | ||
| 40 | ret = z_erofs_map_blocks_iter(inode, &map, | ||
| 41 | @@ -420,10 +422,28 @@ static int erofs_verify_inode_data(struct erofs_inode *inode, int outfd) | ||
| 42 | if (!(map.m_flags & EROFS_MAP_MAPPED) || !fsckcfg.check_decomp) | ||
| 43 | continue; | ||
| 44 | |||
| 45 | - if (map.m_plen > raw_size) { | ||
| 46 | - raw_size = map.m_plen; | ||
| 47 | - raw = realloc(raw, raw_size); | ||
| 48 | - BUG_ON(!raw); | ||
| 49 | + if (map.m_plen > Z_EROFS_PCLUSTER_MAX_SIZE) { | ||
| 50 | + if (compressed) { | ||
| 51 | + erofs_err("invalid pcluster size %" PRIu64 " @ offset %" PRIu64 " of nid %" PRIu64, | ||
| 52 | + map.m_plen, map.m_la, | ||
| 53 | + inode->nid | 0ULL); | ||
| 54 | + ret = -EFSCORRUPTED; | ||
| 55 | + goto out; | ||
| 56 | + } | ||
| 57 | + alloc_rawsize = Z_EROFS_PCLUSTER_MAX_SIZE; | ||
| 58 | + } else { | ||
| 59 | + alloc_rawsize = map.m_plen; | ||
| 60 | + } | ||
| 61 | + | ||
| 62 | + if (alloc_rawsize > raw_size) { | ||
| 63 | + char *newraw = realloc(raw, alloc_rawsize); | ||
| 64 | + | ||
| 65 | + if (!newraw) { | ||
| 66 | + ret = -ENOMEM; | ||
| 67 | + goto out; | ||
| 68 | + } | ||
| 69 | + raw = newraw; | ||
| 70 | + raw_size = alloc_rawsize; | ||
| 71 | } | ||
| 72 | |||
| 73 | if (compressed) { | ||
| 74 | @@ -434,18 +454,26 @@ static int erofs_verify_inode_data(struct erofs_inode *inode, int outfd) | ||
| 75 | } | ||
| 76 | ret = z_erofs_read_one_data(inode, &map, raw, buffer, | ||
| 77 | 0, map.m_llen, false); | ||
| 78 | - } else { | ||
| 79 | - ret = erofs_read_one_data(&map, raw, 0, map.m_plen); | ||
| 80 | - } | ||
| 81 | - if (ret) | ||
| 82 | - goto out; | ||
| 83 | + if (ret) | ||
| 84 | + goto out; | ||
| 85 | |||
| 86 | - if (outfd >= 0 && write(outfd, compressed ? buffer : raw, | ||
| 87 | - map.m_llen) < 0) { | ||
| 88 | - erofs_err("I/O error occurred when verifying data chunk @ nid %llu", | ||
| 89 | - inode->nid | 0ULL); | ||
| 90 | - ret = -EIO; | ||
| 91 | - goto out; | ||
| 92 | + if (outfd >= 0 && write(outfd, buffer, map.m_llen) < 0) | ||
| 93 | + goto fail_eio; | ||
| 94 | + } else { | ||
| 95 | + u64 p = 0; | ||
| 96 | + do { | ||
| 97 | + u64 count = min_t(u64, alloc_rawsize, | ||
| 98 | + map.m_llen); | ||
| 99 | + | ||
| 100 | + ret = erofs_read_one_data(&map, raw, p, count); | ||
| 101 | + if (ret) | ||
| 102 | + goto out; | ||
| 103 | + | ||
| 104 | + if (outfd >= 0 && write(outfd, raw, count) < 0) | ||
| 105 | + goto fail_eio; | ||
| 106 | + map.m_llen -= count; | ||
| 107 | + p += count; | ||
| 108 | + } while (map.m_llen); | ||
| 109 | } | ||
| 110 | } | ||
| 111 | |||
| 112 | @@ -461,6 +489,12 @@ out: | ||
| 113 | if (buffer) | ||
| 114 | free(buffer); | ||
| 115 | return ret < 0 ? ret : 0; | ||
| 116 | + | ||
| 117 | +fail_eio: | ||
| 118 | + erofs_err("I/O error occurred when verifying data chunk @ nid %llu", | ||
| 119 | + inode->nid | 0ULL); | ||
| 120 | + ret = -EIO; | ||
| 121 | + goto out; | ||
| 122 | } | ||
| 123 | |||
| 124 | static inline int erofs_extract_dir(struct erofs_inode *inode) | ||
| 125 | -- | ||
| 126 | 2.25.1 | ||
| 127 | |||
diff --git a/meta/recipes-devtools/erofs-utils/erofs-utils_1.5.bb b/meta/recipes-devtools/erofs-utils/erofs-utils_1.5.bb index 2b5861882d..d7e646a66c 100644 --- a/meta/recipes-devtools/erofs-utils/erofs-utils_1.5.bb +++ b/meta/recipes-devtools/erofs-utils/erofs-utils_1.5.bb | |||
| @@ -10,6 +10,10 @@ SRC_URI = "git://git.kernel.org/pub/scm/linux/kernel/git/xiang/erofs-utils.git;b | |||
| 10 | file://0001-configure-use-AC_SYS_LARGEFILE.patch \ | 10 | file://0001-configure-use-AC_SYS_LARGEFILE.patch \ |
| 11 | file://0002-erofs-replace-l-stat64-by-equivalent-l-stat.patch \ | 11 | file://0002-erofs-replace-l-stat64-by-equivalent-l-stat.patch \ |
| 12 | file://0003-internal.h-Make-LFS-mandatory-for-all-usecases.patch \ | 12 | file://0003-internal.h-Make-LFS-mandatory-for-all-usecases.patch \ |
| 13 | file://CVE-2023-33551.patch \ | ||
| 14 | file://CVE-2023-33552-1.patch \ | ||
| 15 | file://CVE-2023-33552-2.patch \ | ||
| 16 | file://CVE-2023-33552-3.patch \ | ||
| 13 | " | 17 | " |
| 14 | 18 | ||
| 15 | UPSTREAM_CHECK_GITTAGREGEX = "v(?P<pver>(\d+(\.\d+)+))" | 19 | UPSTREAM_CHECK_GITTAGREGEX = "v(?P<pver>(\d+(\.\d+)+))" |
