erofs_extract_symlink() allocates a buffer using malloc(i_size + 1)
where i_size is a 64-bit value read directly from the on-disk inode
with no upper bound validation. When i_size equals UINT64_MAX, the
addition wraps to zero, and malloc(0) returns a minimal allocation.
The subsequent erofs_pread() writes i_size bytes into this tiny
buffer.

Reported-by: Tristan <[email protected]>
Closes: 
https://lore.kernel.org/r/CAA1XrhPMekMqAnRkC-jV9rTsO4LHjzh=kxn6zqkmgbrqfrn...@mail.gmail.com/5-symlink-integer-overflow.txt
Signed-off-by: Gao Xiang <[email protected]>
---
 fsck/main.c          | 5 +++--
 include/erofs/defs.h | 9 +++++++++
 2 files changed, 12 insertions(+), 2 deletions(-)

diff --git a/fsck/main.c b/fsck/main.c
index 21ada195edab..f7f1387fe642 100644
--- a/fsck/main.c
+++ b/fsck/main.c
@@ -784,6 +784,7 @@ static inline int erofs_extract_symlink(struct erofs_inode 
*inode)
 {
        struct erofs_vfile vf;
        bool tryagain = true;
+       erofs_off_t bufsz;
        int ret;
        char *buf = NULL;
 
@@ -794,8 +795,8 @@ static inline int erofs_extract_symlink(struct erofs_inode 
*inode)
        if (ret)
                return ret;
 
-       buf = malloc(inode->i_size + 1);
-       if (!buf) {
+       if (check_add_overflow(inode->i_size, (erofs_off_t)1, &bufsz) ||
+           (buf = malloc(bufsz))) {
                ret = -ENOMEM;
                goto out;
        }
diff --git a/include/erofs/defs.h b/include/erofs/defs.h
index 8151b76ad0f5..fabd867d159c 100644
--- a/include/erofs/defs.h
+++ b/include/erofs/defs.h
@@ -392,6 +392,15 @@ unsigned long __roundup_pow_of_two(unsigned long n)
 #define __erofs_stringify_1(x...)      #x
 #define __erofs_stringify(x...)                __erofs_stringify_1(x)
 
+#define check_add_overflow(a, b, d) ({         \
+       typeof(a) __a = (a);                    \
+       typeof(b) __b = (b);                    \
+       typeof(d) __d = (d);                    \
+       (void) (&__a == &__b);                  \
+       (void) (&__a == __d);                   \
+       __builtin_add_overflow(__a, __b, __d);  \
+})
+
 #define check_sub_overflow(a, b, d) ({         \
        typeof(a) __a = (a);                    \
        typeof(b) __b = (b);                    \
-- 
2.43.5


Reply via email to