Home Home > GIT Browse
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTakashi Iwai <tiwai@suse.de>2018-10-12 12:12:51 +0200
committerTakashi Iwai <tiwai@suse.de>2018-10-12 12:13:01 +0200
commit3e85709fcaf3054fd0726e47406a51a2a2eaf040 (patch)
treec02531984257902ee51ed3c79a1021b378b29a68
parent23943c6c9ec898f6f892949b0341c778ede40450 (diff)
squashfs: be more careful about metadata corruption
(bsc#1051510).
-rw-r--r--patches.fixes/squashfs-be-more-careful-about-metadata-corruption.patch106
-rw-r--r--series.conf1
2 files changed, 107 insertions, 0 deletions
diff --git a/patches.fixes/squashfs-be-more-careful-about-metadata-corruption.patch b/patches.fixes/squashfs-be-more-careful-about-metadata-corruption.patch
new file mode 100644
index 0000000000..d2f1e28b72
--- /dev/null
+++ b/patches.fixes/squashfs-be-more-careful-about-metadata-corruption.patch
@@ -0,0 +1,106 @@
+From 01cfb7937a9af2abb1136c7e89fbf3fd92952956 Mon Sep 17 00:00:00 2001
+From: Linus Torvalds <torvalds@linux-foundation.org>
+Date: Sun, 29 Jul 2018 12:44:46 -0700
+Subject: [PATCH] squashfs: be more careful about metadata corruption
+Git-commit: 01cfb7937a9af2abb1136c7e89fbf3fd92952956
+Patch-mainline: v4.18-rc7
+References: bsc#1051510
+
+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@gmail.com>
+Cc: Al Viro <viro@zeniv.linux.org.uk>
+Cc: Phillip Lougher <phillip@squashfs.org.uk>
+Cc: stable@kernel.org
+Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
+Acked-by: Takashi Iwai <tiwai@suse.de>
+
+---
+ fs/squashfs/cache.c | 3 +++
+ fs/squashfs/file.c | 8 ++++++--
+ fs/squashfs/fragment.c | 4 +---
+ fs/squashfs/squashfs_fs.h | 6 ++++++
+ 4 files changed, 16 insertions(+), 5 deletions(-)
+
+diff --git a/fs/squashfs/cache.c b/fs/squashfs/cache.c
+index 23813c078cc9..0839efa720b3 100644
+--- a/fs/squashfs/cache.c
++++ b/fs/squashfs/cache.c
+@@ -350,6 +350,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 13d80947bf9e..fcff2e0487fe 100644
+--- a/fs/squashfs/file.c
++++ b/fs/squashfs/file.c
+@@ -194,7 +194,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;
+@@ -367,7 +371,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 0ed6edbc5c71..86ad9a4b8c36 100644
+--- a/fs/squashfs/fragment.c
++++ b/fs/squashfs/fragment.c
+@@ -61,9 +61,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 24d12fd14177..4e6853f084d0 100644
+--- a/fs/squashfs/squashfs_fs.h
++++ b/fs/squashfs/squashfs_fs.h
+@@ -129,6 +129,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.19.0
+
diff --git a/series.conf b/series.conf
index 5325826b33..074baab154 100644
--- a/series.conf
+++ b/series.conf
@@ -16968,6 +16968,7 @@
patches.drivers/i2c-davinci-Avoid-zero-value-of-CLKH
patches.drivers/i2c-imx-Fix-reinit_completion-use.patch
patches.drivers/random-mix-rdrand-with-entropy-sent-in-from-userspac
+ patches.fixes/squashfs-be-more-careful-about-metadata-corruption.patch
patches.fixes/ext4-fix-false-negatives-and-false-positives-in-ext4.patch
patches.fixes/ext4-fix-inline-data-updates-with-checksums-enabled.patch
patches.fixes/ext4-check-for-allocation-block-validity-with-block-.patch