[PATCH 1/6] squashfs: be more careful about metadata corruption
Ahmad Fatoum
a.fatoum at pengutronix.de
Tue Jul 16 23:33:23 PDT 2024
This is a port of Linux commit 01cfb7937a9af2abb1136c7e89fbf3fd92952956:
| Author: Linus Torvalds <torvalds at linux-foundation.org>
| AuthorDate: Sun Jul 29 12:44:46 2018 -0700
|
| Anatoly Trosinenko reports that a corrupted squashfs image can cause a
| kernel oops. It turns out that squashfs can end up being confused about
| negative fragment lengths.
|
| The regular squashfs_read_data() does check for negative lengths, but
| squashfs_read_metadata() did not, and the fragment size code just
| blindly trusted the on-disk value. Fix both the fragment parsing and
| the metadata reading code.
|
| Reported-by: Anatoly Trosinenko <anatoly.trosinenko at gmail.com>
| Cc: Al Viro <viro at zeniv.linux.org.uk>
| Cc: Phillip Lougher <phillip at squashfs.org.uk>
| Cc: stable at kernel.org
| Signed-off-by: Linus Torvalds <torvalds at linux-foundation.org>
Reported-by: Richard Weinberger <richard at sigma-star.at>
Signed-off-by: Ahmad Fatoum <a.fatoum at pengutronix.de>
---
fs/squashfs/cache.c | 3 +++
fs/squashfs/file.c | 8 ++++++--
fs/squashfs/fragment.c | 4 +---
fs/squashfs/squashfs_fs.h | 11 +++++++++++
4 files changed, 21 insertions(+), 5 deletions(-)
diff --git a/fs/squashfs/cache.c b/fs/squashfs/cache.c
index 766bc99493b9..5a027d6fe5d0 100644
--- a/fs/squashfs/cache.c
+++ b/fs/squashfs/cache.c
@@ -284,6 +284,9 @@ int squashfs_read_metadata(struct super_block *sb, void *buffer,
TRACE("Entered squashfs_read_metadata [%llx:%x]\n", *block, *offset);
+ if (unlikely(length < 0))
+ return -EIO;
+
while (length) {
entry = squashfs_cache_get(sb, msblk->block_cache, *block, 0);
if (entry->error) {
diff --git a/fs/squashfs/file.c b/fs/squashfs/file.c
index 0806f90b9667..1413ef7ecbd8 100644
--- a/fs/squashfs/file.c
+++ b/fs/squashfs/file.c
@@ -169,7 +169,11 @@ static long long read_indexes(struct super_block *sb, int n,
}
for (i = 0; i < blocks; i++) {
- int size = le32_to_cpu(blist[i]);
+ int size = squashfs_block_size(blist[i]);
+ if (size < 0) {
+ err = size;
+ goto failure;
+ }
block += SQUASHFS_COMPRESSED_SIZE_BLOCK(size);
}
n -= blocks;
@@ -340,7 +344,7 @@ static int read_blocklist(struct inode *inode, int index, u64 *block)
sizeof(size));
if (res < 0)
return res;
- return le32_to_cpu(size);
+ return squashfs_block_size(size);
}
/* Copy data into page cache */
diff --git a/fs/squashfs/fragment.c b/fs/squashfs/fragment.c
index 2b99ff52e334..343444000e02 100644
--- a/fs/squashfs/fragment.c
+++ b/fs/squashfs/fragment.c
@@ -56,9 +56,7 @@ int squashfs_frag_lookup(struct super_block *sb, unsigned int fragment,
return size;
*fragment_block = le64_to_cpu(fragment_entry.start_block);
- size = le32_to_cpu(fragment_entry.size);
-
- return size;
+ return squashfs_block_size(fragment_entry.size);
}
diff --git a/fs/squashfs/squashfs_fs.h b/fs/squashfs/squashfs_fs.h
index 279a3db1bcb2..6ce6ed01ba76 100644
--- a/fs/squashfs/squashfs_fs.h
+++ b/fs/squashfs/squashfs_fs.h
@@ -1,5 +1,10 @@
#ifndef SQUASHFS_FS
#define SQUASHFS_FS
+
+#include <asm/byteorder.h>
+#include <linux/types.h>
+#include <linux/errno.h>
+
/*
* Squashfs
*
@@ -125,6 +130,12 @@
#define SQUASHFS_COMPRESSED_BLOCK(B) (!((B) & SQUASHFS_COMPRESSED_BIT_BLOCK))
+static inline int squashfs_block_size(__le32 raw)
+{
+ u32 size = le32_to_cpu(raw);
+ return (size >> 25) ? -EIO : size;
+}
+
/*
* Inode number ops. Inodes consist of a compressed block number, and an
* uncompressed offset within that block
--
2.39.2
More information about the barebox
mailing list